Browse Source

fixed OSwitch, added OCallClosure, started HVirtual

Nicolas Cannasse 9 years ago
parent
commit
8776783923
1 changed files with 52 additions and 23 deletions
  1. 52 23
      genhl.ml

+ 52 - 23
genhl.ml

@@ -179,7 +179,7 @@ type opcode =
 	| OEnumIndex of reg * reg
 	| OEnumIndex of reg * reg
 	| OEnumField of reg * reg * field index * int
 	| OEnumField of reg * reg * field index * int
 	| OSetEnumField of reg * int * reg
 	| OSetEnumField of reg * int * reg
-	| OSwitch of reg * int array
+	| OSwitch of reg * int array * int
 	| ONullCheck of reg
 	| ONullCheck of reg
 	| OTrap of reg * int
 	| OTrap of reg * int
 	| OEndTrap of unused
 	| OEndTrap of unused
@@ -2309,7 +2309,7 @@ and eval_expr ctx e =
 			if !max > 255 || cases = [] then raise Exit;
 			if !max > 255 || cases = [] then raise Exit;
 			let ridx = eval_to ctx en HI32 in
 			let ridx = eval_to ctx en HI32 in
 			let indexes = Array.make (!max + 1) 0 in
 			let indexes = Array.make (!max + 1) 0 in
-			op ctx (OSwitch (ridx,indexes));
+			op ctx (OSwitch (ridx,indexes,0));
 			let switch_pos = current_pos ctx in
 			let switch_pos = current_pos ctx in
 			(match def with
 			(match def with
 			| None ->
 			| None ->
@@ -2326,6 +2326,7 @@ and eval_expr ctx e =
 				op ctx (OMov (r,re));
 				op ctx (OMov (r,re));
 				jends := jump ctx (fun i -> OJAlways i) :: !jends
 				jends := jump ctx (fun i -> OJAlways i) :: !jends
 			) cases;
 			) cases;
+			DynArray.set ctx.m.mops (switch_pos - 1) (OSwitch (ridx,indexes,current_pos ctx - switch_pos));
 			List.iter (fun j -> j()) (!jends);
 			List.iter (fun j -> j()) (!jends);
 		with Exit ->
 		with Exit ->
 			let jends = ref [] in
 			let jends = ref [] in
@@ -3208,6 +3209,7 @@ let check code =
 				(match ftypes.(f) with
 				(match ftypes.(f) with
 				| HFun (t :: tl, tret) ->
 				| HFun (t :: tl, tret) ->
 					reg arg t;
 					reg arg t;
+					if not (is_nullable t) then error (reg_inf r ^ " should be nullable");
 					reg r (HFun (tl,tret));
 					reg r (HFun (tl,tret));
 				| _ -> assert false);
 				| _ -> assert false);
 			| OThrow r ->
 			| OThrow r ->
@@ -3327,9 +3329,10 @@ let check code =
 					let _, _, tl = e.efields.(0) in
 					let _, _, tl = e.efields.(0) in
 					check (rtype r) tl.(i)
 					check (rtype r) tl.(i)
 				| _ -> is_enum e)
 				| _ -> is_enum e)
-			| OSwitch (r,idx) ->
+			| OSwitch (r,idx,eend) ->
 				reg r HI32;
 				reg r HI32;
-				Array.iter can_jump idx
+				Array.iter can_jump idx;
+				can_jump eend
 			| ONullCheck r ->
 			| ONullCheck r ->
 				ignore(rtype r)
 				ignore(rtype r)
 			| OTrap (r, idx) ->
 			| OTrap (r, idx) ->
@@ -4308,7 +4311,7 @@ let interp code =
 					check rv fields.(i) (fun() -> "enumfield");
 					check rv fields.(i) (fun() -> "enumfield");
 					vl.(i) <- rv
 					vl.(i) <- rv
 				| _ -> assert false)
 				| _ -> assert false)
-			| OSwitch (r, indexes) ->
+			| OSwitch (r, indexes, _) ->
 				(match get r with
 				(match get r with
 				| VInt i ->
 				| VInt i ->
 					let i = Int32.to_int i in
 					let i = Int32.to_int i in
@@ -5226,12 +5229,13 @@ let write_code ch code =
 			byte oid;
 			byte oid;
 			write_index r;
 			write_index r;
 			write_type t
 			write_type t
-		| OSwitch (r,pl) ->
+		| OSwitch (r,pl,eend) ->
 			byte oid;
 			byte oid;
 			let n = Array.length pl in
 			let n = Array.length pl in
 			if n > 0xFF then assert false;
 			if n > 0xFF then assert false;
 			byte n;
 			byte n;
-			Array.iter write_index pl
+			Array.iter write_index pl;
+			write_index eend
 		| OEnumField (r,e,i,idx) ->
 		| OEnumField (r,e,i,idx) ->
 			byte oid;
 			byte oid;
 			write_index r;
 			write_index r;
@@ -5456,7 +5460,7 @@ let ostr o =
 	| OEnumIndex (r,e) -> Printf.sprintf "enumindex %d, %d" r e
 	| OEnumIndex (r,e) -> Printf.sprintf "enumindex %d, %d" r e
 	| OEnumField (r,e,i,n) -> Printf.sprintf "enumfield %d, %d[%d:%d]" r e i n
 	| OEnumField (r,e,i,n) -> Printf.sprintf "enumfield %d, %d[%d:%d]" r e i n
 	| OSetEnumField (e,i,r) -> Printf.sprintf "setenumfield %d[%d], %d" e i r
 	| OSetEnumField (e,i,r) -> Printf.sprintf "setenumfield %d[%d], %d" e i r
-	| OSwitch (r,idx) -> Printf.sprintf "switch %d [%s]" r (String.concat "," (Array.to_list (Array.map string_of_int idx)))
+	| OSwitch (r,idx,eend) -> Printf.sprintf "switch %d [%s] %d" r (String.concat "," (Array.to_list (Array.map string_of_int idx))) eend
 	| ONullCheck r -> Printf.sprintf "nullcheck %d" r
 	| ONullCheck r -> Printf.sprintf "nullcheck %d" r
 	| OTrap (r,i) -> Printf.sprintf "trap %d, %d" r i
 	| OTrap (r,i) -> Printf.sprintf "trap %d, %d" r i
 	| OEndTrap _ -> "endtrap"
 	| OEndTrap _ -> "endtrap"
@@ -5733,7 +5737,7 @@ let write_c version ch (code:code) =
 	Array.iter (fun f ->
 	Array.iter (fun f ->
 		match f.ftype with
 		match f.ftype with
 		| HFun (args,t) ->
 		| HFun (args,t) ->
-			sexpr "%s %s(%s)" (ctype t) (fundecl_name f) (String.concat "," (List.map ctype args));
+			sexpr "static %s %s(%s)" (ctype t) (fundecl_name f) (String.concat "," (List.map ctype args));
 			Array.set tfuns f.findex (args,t);
 			Array.set tfuns f.findex (args,t);
 			funnames.(f.findex) <- fundecl_name f;
 			funnames.(f.findex) <- fundecl_name f;
 		| _ ->
 		| _ ->
@@ -5760,11 +5764,11 @@ let write_c version ch (code:code) =
 	line "";
 	line "";
 	line "// Types values data";
 	line "// Types values data";
 	DynArray.iteri (fun i t ->
 	DynArray.iteri (fun i t ->
+		let field_value (name,name_id,t) =
+			sprintf "{(const uchar*)string$%d, %s, %ld}" name_id (type_value t) (hash name)
+		in
 		match t with
 		match t with
 		| HObj o ->
 		| HObj o ->
-			let field_value (name,name_id,t) =
-				sprintf "{(const uchar*)string$%d, %s, %ld}" name_id (type_value t) (hash name)
-			in
 			let proto_value p =
 			let proto_value p =
 				sprintf "{(const uchar*)string$%d, %d, %d, %ld}" p.fid p.fmethod (match p.fvirtual with None -> -1 | Some i -> i) (hash p.fname)
 				sprintf "{(const uchar*)string$%d, %d, %d, %ld}" p.fid p.fmethod (match p.fvirtual with None -> -1 | Some i -> i) (hash p.fname)
 			in
 			in
@@ -5806,6 +5810,18 @@ let write_c version ch (code:code) =
 				constr_name
 				constr_name
 			] in
 			] in
 			sexpr "static hl_type_enum enum$%d = {%s}" i (String.concat "," efields);
 			sexpr "static hl_type_enum enum$%d = {%s}" i (String.concat "," efields);
+		| HVirtual v ->
+			let fields_name =
+				if Array.length v.vfields = 0 then "NULL" else
+				let name = sprintf "vfields$%d" i in
+				sexpr "static hl_obj_field %s[] = {%s}" name (String.concat "," (List.map field_value (Array.to_list v.vfields)));
+				name
+			in
+			let vfields = [
+				string_of_int (Array.length v.vfields) ^ " PAD_64_VAL";
+				fields_name
+			] in
+			sexpr "static hl_type_virtual virt$%d = {%s}" i (String.concat "," vfields);
 		| _ ->
 		| _ ->
 			()
 			()
 	) types.arr;
 	) types.arr;
@@ -5833,6 +5849,8 @@ let write_c version ch (code:code) =
 			sexpr "type$%d.obj = &obj$%d" i i;
 			sexpr "type$%d.obj = &obj$%d" i i;
 		| HEnum _ ->
 		| HEnum _ ->
 			sexpr "type$%d.tenum = &enum$%d" i i;
 			sexpr "type$%d.tenum = &enum$%d" i i;
+		| HVirtual _ ->
+			sexpr "type$%d.virt = &virt$%d" i i;
 		| _ ->
 		| _ ->
 			()
 			()
 	) types.arr;
 	) types.arr;
@@ -5869,6 +5887,10 @@ let write_c version ch (code:code) =
 			else Printf.sprintf "((%s)%s)" (ctype t) (reg r)
 			else Printf.sprintf "((%s)%s)" (ctype t) (reg r)
 		in
 		in
 
 
+		let rfun r args t =
+			sprintf "((%s (*)(%s))%s->fun)" (ctype t) (String.concat "," (List.map ctype args)) (reg r)
+		in
+
 		let rassign r t =
 		let rassign r t =
 			let rt = rtype r in
 			let rt = rtype r in
 			if t = HVoid then "" else
 			if t = HVoid then "" else
@@ -5901,7 +5923,8 @@ let write_c version ch (code:code) =
 				let name, t = resolve_field o fid in
 				let name, t = resolve_field o fid in
 				sexpr "%s%s->%s" (rassign r t) (reg obj) (ident name)
 				sexpr "%s%s->%s" (rassign r t) (reg obj) (ident name)
 			| HVirtual v ->
 			| HVirtual v ->
-				sexpr "hl_fatal(\"%s\")" "GETFIELD-VIRTUAL"
+				let _, _, t = v.vfields.(fid) in
+				sexpr "%s%s->indexes[%d] ? (*(%s*)(%s->fields_data+%s->indexes[%d])) : (%s)hl_fatal(\"dyn_get\")" (rassign r t) (reg obj) fid (ctype t) (reg obj) (reg obj) fid (ctype t)
 			| _ ->
 			| _ ->
 				assert false
 				assert false
 		in
 		in
@@ -5940,6 +5963,9 @@ let write_c version ch (code:code) =
 				if not (has_label addr) then output_at addr OOLabel;
 				if not (has_label addr) then output_at addr OOLabel;
 				label
 				label
 			in
 			in
+			let todo() =
+				sexpr "hl_fatal(\"%s\")" (ostr op)
+			in
 			match op with
 			match op with
 			| OMov (r,v) ->
 			| OMov (r,v) ->
 				if rtype r <> HVoid then sexpr "%s = %s" (reg r) (rcast v (rtype r))
 				if rtype r <> HVoid then sexpr "%s = %s" (reg r) (rcast v (rtype r))
@@ -6018,8 +6044,16 @@ let write_c version ch (code:code) =
 	(*
 	(*
 	| OCallMethod of reg * field index * reg list
 	| OCallMethod of reg * field index * reg list
 	| OCallThis of reg * field index * reg list
 	| OCallThis of reg * field index * reg list
-	| OCallClosure of reg * reg * reg list
 	*)
 	*)
+			| OCallClosure (r,cl,pl) ->
+				(match rtype cl with
+				| HDyn ->
+					todo() (* dyn_call *)
+				| HFun (args,ret) ->
+					let sargs = String.concat "," (List.map2 rcast pl args) in
+					sexpr "%s%s->hasValue ? %s((vdynamic*)%s->value%s) : %s(%s)" (rassign r ret) (reg cl) (rfun cl (HDyn :: args) ret) (reg cl) (if sargs = "" then "" else "," ^ sargs) (rfun cl args ret) sargs
+				| _ ->
+					assert false)
 			| OGetFunction (r,fid) ->
 			| OGetFunction (r,fid) ->
 				sexpr "%s = &cl$%d" (reg r) fid
 				sexpr "%s = &cl$%d" (reg r) fid
 	(*
 	(*
@@ -6163,25 +6197,20 @@ let write_c version ch (code:code) =
 	| OEnumField of reg * reg * field index * int
 	| OEnumField of reg * reg * field index * int
 	| OSetEnumField of reg * int * reg
 	| OSetEnumField of reg * int * reg
 	*)
 	*)
-			| OSwitch (r,idx) ->
+			| OSwitch (r,idx,eend) ->
 				Printf.ksprintf line "switch(%s) {" (reg r);
 				Printf.ksprintf line "switch(%s) {" (reg r);
 				block();
 				block();
 				output_at2 (i + 1) [OODefault;OOIncreaseIndent];
 				output_at2 (i + 1) [OODefault;OOIncreaseIndent];
 				Array.iteri (fun k delta -> output_at2 (delta + i + 1) [OODecreaseIndent;OOCase k;OOIncreaseIndent]) idx;
 				Array.iteri (fun k delta -> output_at2 (delta + i + 1) [OODecreaseIndent;OOCase k;OOIncreaseIndent]) idx;
-				(* TOOD: This is brittle and could be broken by DCE. Need a better way to determine where the switch ends. *)
-				let first_case = i + idx.(0) in
-				begin match f.code.(first_case) with
-					| OJAlways j -> output_at2 (first_case + j + 1) [OODecreaseIndent;OODecreaseIndent;OOEndBlock];
-					| _ -> assert false
-				end
+				output_at2 (i + 1 + eend) [OODecreaseIndent;OODecreaseIndent;OOEndBlock];
 			| ONullCheck r ->
 			| ONullCheck r ->
-				sexpr "if( %s == NULL ) hl_error_msg(USTR(\"Null access\"))" (reg r)
+				sexpr "if( %s == NULL ) hl_null_access()" (reg r)
 	(*
 	(*
 	| OTrap of reg * int
 	| OTrap of reg * int
 	| OEndTrap of unused
 	| OEndTrap of unused
 	| ODump of reg*)
 	| ODump of reg*)
 			| _ ->
 			| _ ->
-				sexpr "hl_fatal(\"%s\")" (ostr op)
+				todo()
 		) f.code;
 		) f.code;
 		unblock();
 		unblock();
 		line "}";
 		line "}";