2
0
Эх сурвалжийг харах

Xml (with callbacks) and Process (with buffer copy) api now supported with neko bridge

Nicolas Cannasse 13 жил өмнө
parent
commit
016b40b811
1 өөрчлөгдсөн 155 нэмэгдсэн , 23 устгасан
  1. 155 23
      interp.ml

+ 155 - 23
interp.ml

@@ -60,6 +60,7 @@ and vabstract =
 	| AUnsafe of Obj.t
 	| AUnsafe of Obj.t
 	| ALazyType of (unit -> Type.t) ref
 	| ALazyType of (unit -> Type.t) ref
 	| ANekoAbstract of Extc.value
 	| ANekoAbstract of Extc.value
+	| ANekoBuffer of value
 
 
 and vfunction =
 and vfunction =
 	| Fun0 of (unit -> value)
 	| Fun0 of (unit -> value)
@@ -452,11 +453,11 @@ let neko =
 	let vm = Extc.dlcall1 (load "neko_vm_alloc") null in
 	let vm = Extc.dlcall1 (load "neko_vm_alloc") null in
 	ignore(Extc.dlcall1 (load "neko_vm_select") vm);
 	ignore(Extc.dlcall1 (load "neko_vm_select") vm);
 	let loader = Extc.dlcall2 (load "neko_default_loader") null null in
 	let loader = Extc.dlcall2 (load "neko_default_loader") null null in
-	let lp_id = Extc.dlcall1 (load "neko_val_id") (Extc.dlstring "loadprim") in
-	let ocall2 = load "neko_val_ocall2" in
+	let loadprim = Extc.dlcall2 (load "neko_val_field") loader (Extc.dlcall1 (load "neko_val_id") (Extc.dlstring "loadprim")) in
+
 	let callN = load "neko_val_callN" in
 	let callN = load "neko_val_callN" in
 	let callEx = load "neko_val_callEx" in
 	let callEx = load "neko_val_callEx" in
-	let alloc_string = load "neko_alloc_string" in
+	let copy_string = load "neko_copy_string" in
 
 
 	let alloc_root = load "neko_alloc_root" in
 	let alloc_root = load "neko_alloc_root" in
 	let free_root = load "neko_free_root" in
 	let free_root = load "neko_free_root" in
@@ -472,15 +473,19 @@ let neko =
 
 
 	ignore(alloc_root vm);
 	ignore(alloc_root vm);
 	ignore(alloc_root loader);
 	ignore(alloc_root loader);
+	ignore(alloc_root loadprim);
 
 
 	let alloc_string s =
 	let alloc_string s =
-		Extc.dlcall1 alloc_string (Extc.dlstring s)
+		Extc.dlcall2 copy_string (Extc.dlstring s) (Extc.dlint (String.length s))
 	in
 	in
 	let alloc_int (i:int) : Extc.value =
 	let alloc_int (i:int) : Extc.value =
 		Obj.magic i
 		Obj.magic i
 	in
 	in
 	let loadprim n args =
 	let loadprim n args =
-		let p = Extc.dlcall4 ocall2 loader lp_id (alloc_string n) (alloc_int args) in
+		let exc = ref null in
+		let vargs = [|alloc_string n;alloc_int args|] in
+		let p = Extc.dlcall5 callEx loader loadprim (Obj.magic vargs) (Extc.dlint 2) (Obj.magic exc) in
+		if !exc != null then failwith ("Failed ot load " ^ n ^ ":" ^ string_of_int args);
 		ignore(alloc_root p);
 		ignore(alloc_root p);
 		(n,p,args)
 		(n,p,args)
 	in
 	in
@@ -493,21 +498,88 @@ let neko =
 	let val_true = call_raw_prim unser [|alloc_string "T";loader|] in
 	let val_true = call_raw_prim unser [|alloc_string "T";loader|] in
 	let val_false = call_raw_prim unser [|alloc_string "F";loader|] in
 	let val_false = call_raw_prim unser [|alloc_string "F";loader|] in
 	let val_null = call_raw_prim unser [|alloc_string "N";loader|] in
 	let val_null = call_raw_prim unser [|alloc_string "N";loader|] in
+
 	let is_64 = call_raw_prim (loadprim "std@sys_is64" 0) [||] == val_true in
 	let is_64 = call_raw_prim (loadprim "std@sys_is64" 0) [||] == val_true in
+	let ptr_size = if is_64 then 8 else 4 in
+	let val_field v i = Extc.dladdr v (4 + i * ptr_size) in
+
+	(* alloc support *)
+
+	let alloc_function = load "neko_alloc_function" in
+	let alloc_array = load "neko_alloc_array" in
+	let alloc_float = load "neko_alloc_float" in
+	let alloc_object = load "neko_alloc_object" in
+	let alloc_field = load "neko_alloc_field" in
+	let alloc_abstract = load "neko_alloc_abstract" in
+	let val_gc = load "neko_val_gc" in
+	let val_field_name = load "neko_val_field_name" in
+	let val_iter_fields = load "neko_val_iter_fields" in
+	let gen_callback = Extc.dlcaml_callback 2 in
+
+	(* roots *)
+
+	let on_abstract_gc = Extc.dlcaml_callback 1 in
+	let root_index = ref 0 in
+	let roots = Hashtbl.create 0 in	
+	Callback.register "dlcallb1" (fun a ->
+		let index : int = Obj.magic (Extc.dlptr (val_field a 1)) in
+		Hashtbl.remove roots index;
+		null
+	);
 
 
-	(* objects fields support *)
+	(* wrapping *)
 
 
-	let neko_val_iter_fields = load "neko_val_iter_fields" in
+	let copy_string v =
+		let head = Extc.dltoint (Extc.dlptr v) in
+		let size = head lsr 3 in
+		let s = String.create size in
+		Extc.dlmemcpy (Extc.dlstring s) (val_field v 0) size;
+		s
+	in
 
 
-	(* wrapping *)
+	let buffers = ref [] in
 
 
-	let value_neko = function
+	let rec value_neko ?(obj=VNull) = function
 		| VNull -> val_null
 		| VNull -> val_null
 		| VBool b -> if b then val_true else val_false
 		| VBool b -> if b then val_true else val_false
 		| VInt i -> alloc_int i
 		| VInt i -> alloc_int i
 		| VAbstract (ANekoAbstract a) -> a
 		| VAbstract (ANekoAbstract a) -> a
-		| VString s -> alloc_string s (* make a copy *)
-		| _ -> assert false
+		| VAbstract (ANekoBuffer (VString buf)) ->
+			let v = value_neko (VString buf) in
+			buffers := (buf,v) :: !buffers;
+			v
+		| VString s ->
+			let v = alloc_string s in (* make a copy *)			
+			ignore(copy_string v);
+			v
+		| VObject o as obj ->
+			let vo = Extc.dlcall1 alloc_object null in
+			Array.iter (fun (id,v) ->
+				ignore(Extc.dlcall3 alloc_field vo (Extc.dlint id) (value_neko ~obj v))
+			) o.ofields;			
+			vo
+		| VClosure _ ->
+			failwith "Closure not supported"
+		| VFunction f ->
+			let callb = Extc.dlcall3 alloc_function gen_callback (Extc.dlint (-1)) (Obj.magic "<callback>") in
+			let index = !root_index in
+			incr root_index;
+			Hashtbl.add roots index (f,obj);
+			let a = Extc.dlcall2 alloc_abstract null (Obj.magic index) in
+			if Extc.dlptr (val_field a 1) != Obj.magic index then assert false;
+			ignore(Extc.dlcall2 val_gc a on_abstract_gc);
+			Extc.dlsetptr (val_field callb 2) a;
+			callb
+		| VArray a ->
+			let va = Extc.dlcall1 alloc_array (Extc.dlint (Array.length a)) in
+			Array.iteri (fun i v ->
+				Extc.dlsetptr (val_field va i) (value_neko v)
+			) a;
+			va
+		| VFloat f ->
+			Extc.dlcall1 alloc_float (Obj.magic f)
+		| VAbstract _ ->
+			failwith "Abstract not supported"
 	in
 	in
 	let rec neko_value (v:Extc.value) =
 	let rec neko_value (v:Extc.value) =
 		if Obj.is_int (Obj.magic v) then
 		if Obj.is_int (Obj.magic v) then
@@ -517,14 +589,22 @@ let neko =
 			match head land 7 with
 			match head land 7 with
 			| 0 -> VNull
 			| 0 -> VNull
 			| 2 -> VBool (v == val_true)
 			| 2 -> VBool (v == val_true)
-			| 3 -> VString (Extc.dlalloc_mem (Extc.dladdr v 4) (head lsr 3)) (* copy *)
+			| 3 -> VString (copy_string v)
 			| 4 ->
 			| 4 ->
 				let r = ref [] in
 				let r = ref [] in
-				ignore(Extc.dlcall3 neko_val_iter_fields v (Extc.dlcallback 2) (Obj.magic (fun v id -> r := (v,id) :: !r; val_null)));
-				let fields = List.rev_map (fun (v,id) -> (Extc.dltoint id), neko_value v) !r in
+				ignore(Extc.dlcall3 val_iter_fields v (Extc.dlcallback 2) (Obj.magic (fun v id -> r := (v,id) :: !r; val_null)));
+				let ctx = get_ctx() in
+				let fields = List.rev_map (fun (v,id) ->
+					let iid = Extc.dltoint id in
+					if not (Hashtbl.mem ctx.fields_cache iid) then begin
+						let name = copy_string (Extc.dlcall1 val_field_name id) in
+						ignore(hash_field ctx name);
+					end;
+					iid, neko_value v
+				) !r in
 				VObject { ofields = Array.of_list fields; oproto = None }
 				VObject { ofields = Array.of_list fields; oproto = None }
 			| 5 ->
 			| 5 ->
-				VArray (Array.init (head lsr 3) (fun i -> neko_value (Extc.dladdr v (4 + i * (if is_64 then 8 else 4)))))
+				VArray (Array.init (head lsr 3) (fun i -> neko_value (Extc.dlptr (val_field v i))))
 			| 7 ->
 			| 7 ->
 				let r = alloc_root v in
 				let r = alloc_root v in
 				let a = ANekoAbstract v in
 				let a = ANekoAbstract v in
@@ -532,19 +612,42 @@ let neko =
 				VAbstract a
 				VAbstract a
 			| t ->
 			| t ->
 				failwith ("Unsupported Neko value tag " ^ string_of_int t)
 				failwith ("Unsupported Neko value tag " ^ string_of_int t)
-	in	
+	in
+
+	Callback.register "dlcallb2" (fun args nargs ->
+		(* get back the VM env, which was set in value_neko *)
+		let env = Extc.dlptr (Extc.dladdr vm (2 * ptr_size)) in		
+		(* extract the index stored in abstract data *)
+		let index : int = Obj.magic (Extc.dlptr (val_field env 1)) in
+		let f, obj = (try Hashtbl.find roots index with Not_found -> assert false) in
+		let nargs = Extc.dltoint nargs in
+		let rec loop i =
+			if i = nargs then [] else neko_value (Extc.dlptr (Extc.dladdr args (i * ptr_size))) :: loop (i + 1)
+		in
+		let v = (get_ctx()).do_call obj (VFunction f) (loop 0) { psource = "<callback>"; pline = 0; } in
+		value_neko v
+	);
+
 	let callprim (n,p,nargs) args =
 	let callprim (n,p,nargs) args =
 		let arr = Array.of_list (List.map value_neko args) in
 		let arr = Array.of_list (List.map value_neko args) in
 		let exc = ref null in
 		let exc = ref null in
 		if Array.length arr <> nargs then failwith n;
 		if Array.length arr <> nargs then failwith n;
 		let ret = Extc.dlcall5 callEx val_null p (Obj.magic arr) (Extc.dlint nargs) (Obj.magic exc) in
 		let ret = Extc.dlcall5 callEx val_null p (Obj.magic arr) (Extc.dlint nargs) (Obj.magic exc) in
 		if !exc != null then raise (Runtime (neko_value !exc));
 		if !exc != null then raise (Runtime (neko_value !exc));
+		(match !buffers with
+		| [] -> ()
+		| l ->
+			buffers := [];
+			(* copy back data *)
+			List.iter (fun (buf,v) ->
+				Extc.dlmemcpy (Extc.dlstring buf) (val_field v 0) (String.length buf);
+			) l);
 		neko_value ret
 		neko_value ret
 	in
 	in
 	Some {
 	Some {
 		load = loadprim;
 		load = loadprim;
 		call = callprim;
 		call = callprim;
-	}	
+	}
 
 
 (* ---------------------------------------------------------------------- *)
 (* ---------------------------------------------------------------------- *)
 (* BUILTINS *)
 (* BUILTINS *)
@@ -846,6 +949,10 @@ let builtins =
 	 	"version", Fun0 (fun() ->
 	 	"version", Fun0 (fun() ->
 	 		VInt 0
 	 		VInt 0
 	 	);
 	 	);
+	(* extra *)
+		"use_neko_dll", Fun0 (fun() ->
+			VBool (neko <> None)
+		);
 	] in
 	] in
 	let vals = [
 	let vals = [
 		"tnull", VInt 0;
 		"tnull", VInt 0;
@@ -913,7 +1020,7 @@ let std_lib =
 		Unix.inet_addr_of_string str
 		Unix.inet_addr_of_string str
 	in
 	in
 	let int32_op op = Fun2 (fun a b -> make_i32 (op (int32 a) (int32 b))) in
 	let int32_op op = Fun2 (fun a b -> make_i32 (op (int32 a) (int32 b))) in
-	make_library [
+	make_library ([
 	(* math *)
 	(* math *)
 		"math_atan2", Fun2 (fun a b -> VFloat (atan2 (num a) (num b)));
 		"math_atan2", Fun2 (fun a b -> VFloat (atan2 (num a) (num b)));
 		"math_pow", Fun2 (fun a b -> VFloat ((num a) ** (num b)));
 		"math_pow", Fun2 (fun a b -> VFloat ((num a) ** (num b)));
@@ -1603,7 +1710,8 @@ let std_lib =
 			VInt (UTF8.compare (vstring s1) (vstring s2))
 			VInt (UTF8.compare (vstring s1) (vstring s2))
 		);
 		);
 	(* xml *)
 	(* xml *)
-		"parse_xml", Fun2 (fun str o ->
+		"parse_xml", (match neko with
+		| None -> Fun2 (fun str o ->
 			match str, o with
 			match str, o with
 			| VString str, VObject events ->
 			| VString str, VObject events ->
 				let ctx = get_ctx() in
 				let ctx = get_ctx() in
@@ -1635,12 +1743,36 @@ let std_lib =
 				with Xml.Error e -> failwith ("Parser failure (" ^ Xml.error e ^ ")")
 				with Xml.Error e -> failwith ("Parser failure (" ^ Xml.error e ^ ")")
 				| e -> failwith ("Parser failure (" ^ Printexc.to_string e ^ ")"));
 				| e -> failwith ("Parser failure (" ^ Printexc.to_string e ^ ")"));
 				VNull
 				VNull
-			| _ -> error()
+			| _ -> error())
+		| Some neko ->
+			let parse_xml = neko.load "std@parse_xml" 2 in
+			Fun2 (fun str o -> neko.call parse_xml [str;o])			
 		);
 		);
-	(* process *)
-		(* TODO *)
 	(* memory, module, thread : not planned *)
 	(* memory, module, thread : not planned *)
-	]
+	] 
+	(* process *)
+	@ (match neko with
+	| None -> []
+	| Some neko ->
+		let p_run = neko.load "std@process_run" 2 in
+		let p_stdout_read = neko.load "std@process_stdout_read" 4 in
+		let p_stderr_read = neko.load "std@process_stderr_read" 4 in
+		let p_stdin_write = neko.load "std@process_stdin_write" 4 in
+		let p_stdin_close = neko.load "std@process_stdin_close" 1 in
+		let p_exit = neko.load "std@process_exit" 1 in
+		let p_pid = neko.load "std@process_pid" 1 in
+		let p_close = neko.load "std@process_close" 1 in
+	[
+		"process_run", (Fun2 (fun a b -> neko.call p_run [a;b]));
+		"process_stdout_read", (Fun4 (fun a b c d -> neko.call p_stdout_read [a;VAbstract (ANekoBuffer b);c;d]));
+		"process_stderr_read", (Fun4 (fun a b c d -> neko.call p_stderr_read [a;VAbstract (ANekoBuffer b);c;d]));
+		"process_stdin_write", (Fun4 (fun a b c d -> neko.call p_stdin_write [a;b;c;d]));
+		"process_stdin_close", (Fun1 (fun p -> neko.call p_stdin_close [p]));
+		"process_exit", (Fun1 (fun p -> neko.call p_exit [p]));
+		"process_pid", (Fun1 (fun p -> neko.call p_pid [p]));
+		"process_close", (Fun1 (fun p -> neko.call p_close [p]));
+	]))
+
 
 
 (* ---------------------------------------------------------------------- *)
 (* ---------------------------------------------------------------------- *)
 (* REGEXP LIBRARY *)
 (* REGEXP LIBRARY *)