Browse Source

optimized signature() with big structures using O(1) cache lookup

Nicolas Cannasse 13 năm trước cách đây
mục cha
commit
568b4a9b9c
1 tập tin đã thay đổi với 34 bổ sung17 xóa
  1. 34 17
      interp.ml

+ 34 - 17
interp.ml

@@ -61,6 +61,7 @@ and vabstract =
 	| ALazyType of (unit -> Type.t) ref
 	| ALazyType of (unit -> Type.t) ref
 	| ANekoAbstract of Extc.value
 	| ANekoAbstract of Extc.value
 	| ANekoBuffer of value
 	| ANekoBuffer of value
+	| ACacheRef of value
 
 
 and vfunction =
 and vfunction =
 	| Fun0 of (unit -> value)
 	| Fun0 of (unit -> value)
@@ -2119,6 +2120,7 @@ let macro_lib =
 		);
 		);
 		"signature", Fun1 (fun v ->
 		"signature", Fun1 (fun v ->
 			let cache = ref [] in
 			let cache = ref [] in
+			let cache_count = ref 0 in
 			let hfiles = Hashtbl.create 0 in
 			let hfiles = Hashtbl.create 0 in
 			let get_file f =
 			let get_file f =
 				try
 				try
@@ -2128,20 +2130,28 @@ let macro_lib =
 					Hashtbl.add hfiles f ff;
 					Hashtbl.add hfiles f ff;
 					ff
 					ff
 			in
 			in
+			let do_cache (v:value) (v2:value) =
+				(*
+					tricky : we need to have a quick not-linear cache based on objects address
+					but we can't use address since the GC might be triggered here.
+					Instead let's mutate the object temporary.
+				*)
+				let vt = Obj.repr v in
+				let old = Obj.tag vt in
+				let old_val = Obj.field vt 0 in
+				let abstract_tag = 7 in
+				Obj.set_tag vt abstract_tag;
+				Obj.set_field vt 0 (Obj.repr (ACacheRef v2));
+				cache := (vt,old,old_val) :: !cache;
+				incr cache_count
+			in
 			let rec loop v =
 			let rec loop v =
 				match v with
 				match v with
 				| VNull | VBool _ | VInt _ | VFloat _ | VString _ -> v
 				| VNull | VBool _ | VInt _ | VFloat _ | VString _ -> v
-				| VAbstract (AInt32 _) -> v
-				| VAbstract (APos p) -> VAbstract (APos { p with Ast.pfile = get_file p.Ast.pfile })
-				| _ ->
-					try
-						List.assq v !cache
-					with Not_found ->
-				match v with
 				| VObject o ->
 				| VObject o ->
 					let o2 = { ofields = [||]; oproto = None } in
 					let o2 = { ofields = [||]; oproto = None } in
 					let v2 = VObject o2 in
 					let v2 = VObject o2 in
-					cache := (v,v2) :: !cache;
+					do_cache v v2;
 					Array.iter (fun (f,v) -> if f <> h_class then set_field o2 f (loop v)) o.ofields;
 					Array.iter (fun (f,v) -> if f <> h_class then set_field o2 f (loop v)) o.ofields;
 					(match o.oproto with
 					(match o.oproto with
 					| None -> ()
 					| None -> ()
@@ -2150,34 +2160,41 @@ let macro_lib =
 				| VArray a ->
 				| VArray a ->
 					let a2 = Array.create (Array.length a) VNull in
 					let a2 = Array.create (Array.length a) VNull in
 					let v2 = VArray a2 in
 					let v2 = VArray a2 in
-					cache := (v,v2) :: !cache;
+					do_cache v v2;
 					for i = 0 to Array.length a - 1 do
 					for i = 0 to Array.length a - 1 do
 						a2.(i) <- loop a.(i);
 						a2.(i) <- loop a.(i);
 					done;
 					done;
 					v2
 					v2
 				| VFunction f ->
 				| VFunction f ->
-					let v2 = VFunction (Obj.magic (List.length !cache)) in
-					cache := (v,v2) :: !cache;
+					let v2 = VFunction (Obj.magic !cache_count) in
+					do_cache v v2;
 					v2
 					v2
 				| VClosure (vl,f) ->
 				| VClosure (vl,f) ->
 					let rl = ref [] in
 					let rl = ref [] in
-					let v2 = VClosure (Obj.magic rl, Obj.magic (List.length !cache)) in
-					cache := (v,v2) :: !cache;
+					let v2 = VClosure (Obj.magic rl, Obj.magic !cache_count) in
+					do_cache v v2;
 					rl := List.map loop vl;
 					rl := List.map loop vl;
 					v2
 					v2
+				| VAbstract (AInt32 _) -> v
+				| VAbstract (APos p) -> VAbstract (APos { p with Ast.pfile = get_file p.Ast.pfile })
+				| VAbstract (ACacheRef v) -> v
 				| VAbstract (AHash h) ->
 				| VAbstract (AHash h) ->
 					let h2 = Hashtbl.create 0 in
 					let h2 = Hashtbl.create 0 in
 					let v2 = VAbstract (AHash h2) in
 					let v2 = VAbstract (AHash h2) in
-					cache := (v, v2) :: !cache;
+					do_cache v v2;
 					Hashtbl.iter (fun k v -> Hashtbl.add h2 k (loop v)) h2;
 					Hashtbl.iter (fun k v -> Hashtbl.add h2 k (loop v)) h2;
 					v2
 					v2
 				| VAbstract _ ->
 				| VAbstract _ ->
-					let v2 = VAbstract (Obj.magic (List.length !cache)) in
-					cache := (v, v2) :: !cache;
+					let v2 = VAbstract (Obj.magic !cache_count) in
+					do_cache v v2;
 					v2
 					v2
-				| _ -> assert false
 			in
 			in
 			let v = loop v in
 			let v = loop v in
+			(* restore *)
+			List.iter (fun (vt,tag,field) ->
+				Obj.set_tag vt tag;
+				Obj.set_field vt 0 field;
+			) !cache;
 			VString (Digest.to_hex (Digest.string (Marshal.to_string v [Marshal.Closures])))
 			VString (Digest.to_hex (Digest.string (Marshal.to_string v [Marshal.Closures])))
 		);
 		);
 		"to_complex", Fun1 (fun v ->
 		"to_complex", Fun1 (fun v ->