Browse Source

[cs] unsafe environment

Caue Waneck 13 years ago
parent
commit
39ee15d177
4 changed files with 131 additions and 28 deletions
  1. 6 0
      gencommon.ml
  2. 65 10
      gencs.ml
  3. 54 12
      std/cs/Lib.hx
  4. 6 6
      tests/unit/TestCSharp.hx

+ 6 - 0
gencommon.ml

@@ -5361,6 +5361,12 @@ struct
             match e.eexpr, shallow_expr_type e with
             match e.eexpr, shallow_expr_type e with
               | TVars( (hd1 :: hd2 :: _) as vars ), _ ->
               | TVars( (hd1 :: hd2 :: _) as vars ), _ ->
                 List.iter (fun v -> process_statement { e with eexpr = TVars([v]) }) vars
                 List.iter (fun v -> process_statement { e with eexpr = TVars([v]) }) vars
+              | TCall( { eexpr = TLocal v } as elocal, elist ), _ when String.get v.v_name 0 = '_' && Hashtbl.mem gen.gspecial_vars v.v_name ->
+                new_block := { e with eexpr = TCall( elocal, List.map (fun e ->
+                  match e.eexpr with 
+                    | TBlock _ -> traverse e
+                    | _ -> e
+                ) elist ) } :: !new_block
               | _, Statement | _, Both _ ->
               | _, Statement | _, Both _ ->
                 let e = match e.eexpr with | TReturn (Some ({ eexpr = TThrow _ } as ethrow)) -> ethrow | _ -> e in
                 let e = match e.eexpr with | TReturn (Some ({ eexpr = TThrow _ } as ethrow)) -> ethrow | _ -> e in
                 let kinds = get_kinds e in
                 let kinds = get_kinds e in

+ 65 - 10
gencs.ml

@@ -490,6 +490,7 @@ let rec get_class_modifiers meta cl_type cl_access cl_modifiers =
     (* no abstract for now | (":abstract",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("abstract" :: cl_modifiers) 
     (* no abstract for now | (":abstract",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("abstract" :: cl_modifiers) 
     | (":static",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("static" :: cl_modifiers) TODO: support those types *)
     | (":static",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("static" :: cl_modifiers) TODO: support those types *)
     | (":final",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("sealed" :: cl_modifiers)
     | (":final",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("sealed" :: cl_modifiers)
+    | (":unsafe",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("unsafe" :: cl_modifiers)
     | _ :: meta -> get_class_modifiers meta cl_type cl_access cl_modifiers
     | _ :: meta -> get_class_modifiers meta cl_type cl_access cl_modifiers
 
 
 let rec get_fun_modifiers meta access modifiers =
 let rec get_fun_modifiers meta access modifiers =
@@ -670,6 +671,8 @@ let configure gen =
             | _ -> t_s (run_follow gen t)
             | _ -> t_s (run_follow gen t)
         in
         in
         (check_t_s param) ^ "[]"
         (check_t_s param) ^ "[]"
+      | TInst({ cl_path = (["cs"], "Pointer") }, [ t ]) ->
+        t_s t ^ "*"
       (* end of basic types *)
       (* end of basic types *)
       | TInst ({ cl_kind = KTypeParameter; cl_path=p }, []) -> snd p
       | TInst ({ cl_kind = KTypeParameter; cl_path=p }, []) -> snd p
       | TMono r -> (match !r with | None -> "object" | Some t -> t_s (run_follow gen t))
       | TMono r -> (match !r with | None -> "object" | Some t -> t_s (run_follow gen t))
@@ -756,6 +759,16 @@ let configure gen =
         t_s (TType(t, List.map (fun t -> t_dynamic) t.t_types))
         t_s (TType(t, List.map (fun t -> t_dynamic) t.t_types))
   in
   in
   
   
+  let rec ensure_local e explain =
+    match e.eexpr with 
+      | TLocal _ -> e
+      | TCast(e,_)
+      | TParenthesis e -> ensure_local e explain
+      | _ -> gen.gcon.error ("This function argument " ^ explain ^ " must be a local variable.") e.epos; e
+  in
+  
+  let is_pointer t = match follow t with | TInst({ cl_path = (["cs"], "Pointer") }, _) -> true | _ -> false in
+  
   let expr_s w e =
   let expr_s w e =
     in_value := false;
     in_value := false;
     let rec expr_s w e =
     let rec expr_s w e =
@@ -793,6 +806,7 @@ let configure gen =
           write w (t_s (TInst(runtime_cl, List.map (fun _ -> t_dynamic) runtime_cl.cl_types)));
           write w (t_s (TInst(runtime_cl, List.map (fun _ -> t_dynamic) runtime_cl.cl_types)));
           write w ".undefined";
           write w ".undefined";
         | TLocal { v_name = "__typeof__" } -> write w "typeof"
         | TLocal { v_name = "__typeof__" } -> write w "typeof"
+        | TLocal { v_name = "__sizeof__" } -> write w "sizeof"
         | TLocal var ->
         | TLocal var ->
           write_id w var.v_name
           write_id w var.v_name
         | TEnumField (e, s) ->
         | TEnumField (e, s) ->
@@ -840,6 +854,47 @@ let configure gen =
           write w " )"
           write w " )"
         | TCall ({ eexpr = TLocal( { v_name = "__cs__" } ) }, [ { eexpr = TConst(TString(s)) } ] ) ->
         | TCall ({ eexpr = TLocal( { v_name = "__cs__" } ) }, [ { eexpr = TConst(TString(s)) } ] ) ->
           write w s
           write w s
+        | TCall ({ eexpr = TLocal( { v_name = "__unsafe__" } ) }, [ e ] ) ->
+          write w "unsafe";
+          expr_s w (mk_block e)
+        | TCall ({ eexpr = TLocal( { v_name = "__checked__" } ) }, [ e ] ) ->
+          write w "checked";
+          expr_s w (mk_block e)
+        | TCall ({ eexpr = TLocal( { v_name = "__lock__" } ) }, [ eobj; eblock ] ) ->
+          write w "lock(";
+          expr_s w eobj;
+          write w ")";
+          expr_s w (mk_block eblock)
+        | TCall ({ eexpr = TLocal( { v_name = "__fixed__" } ) }, [ e ] ) ->
+          write w "fixed(";
+          let first = ref true in
+          let rec loop = function
+            | ({ eexpr = TVars([v, Some({ eexpr = TCast( { eexpr = TCast(e, _) }, _) }) ]) } as expr) :: tl when is_pointer v.v_type ->
+              (if !first then first := false else write w ", ");
+              expr_s w { expr with eexpr = TVars([v, Some e]) };
+              loop tl
+            | el when not !first ->
+              write w ")";
+              expr_s w { e with eexpr = TBlock el }
+            | _ -> 
+              trace (debug_expr e);
+              gen.gcon.error "Invalid 'fixed' keyword format" e.epos
+          in
+          (match e.eexpr with
+            | TBlock bl -> loop bl
+            | _ -> 
+              trace "not block";
+              trace (debug_expr e);
+              gen.gcon.error "Invalid 'fixed' keyword format" e.epos
+          )
+        | TCall ({ eexpr = TLocal( { v_name = "__addressOf__" } ) }, [ e ] ) ->
+          let e = ensure_local e "for addressOf" in
+          write w "&";
+          expr_s w e
+        | TCall ({ eexpr = TLocal( { v_name = "__valueOf__" } ) }, [ e ] ) ->
+          write w "*(";
+          expr_s w e;
+          write w ")"
         | TCall ({ eexpr = TLocal( { v_name = "__goto__" } ) }, [ { eexpr = TConst(TInt v) } ] ) ->
         | TCall ({ eexpr = TLocal( { v_name = "__goto__" } ) }, [ { eexpr = TConst(TInt v) } ] ) ->
           print w "goto label%ld" v
           print w "goto label%ld" v
         | TCall ({ eexpr = TLocal( { v_name = "__label__" } ) }, [ { eexpr = TConst(TInt v) } ] ) ->
         | TCall ({ eexpr = TLocal( { v_name = "__label__" } ) }, [ { eexpr = TConst(TInt v) } ] ) ->
@@ -874,25 +929,17 @@ let configure gen =
               write w ">"
               write w ">"
           );
           );
           
           
-          let rec ensure_local e explain =
-            match e.eexpr with 
-              | TLocal _ -> e
-              | TCast(e,_)
-              | TParenthesis e -> ensure_local e explain
-              | _ -> gen.gcon.error ("The function argument of type " ^ explain ^ " must be a local variable.") e.epos; e
-          in
-          
           let rec loop acc elist tlist =
           let rec loop acc elist tlist =
             match elist, tlist with
             match elist, tlist with
               | e :: etl, (_,_,t) :: ttl ->
               | e :: etl, (_,_,t) :: ttl ->
                 (if acc <> 0 then write w ", ");
                 (if acc <> 0 then write w ", ");
                 (match real_type t with
                 (match real_type t with
                   | TType({ t_path = (["cs"], "Ref") }, _) ->
                   | TType({ t_path = (["cs"], "Ref") }, _) ->
-                    let e = ensure_local e "cs.Ref" in
+                    let e = ensure_local e "of type cs.Ref" in
                     write w "ref ";
                     write w "ref ";
                     expr_s w e
                     expr_s w e
                   | TType({ t_path = (["cs"], "Out") }, _) ->
                   | TType({ t_path = (["cs"], "Out") }, _) ->
-                    let e = ensure_local e "cs.Out" in
+                    let e = ensure_local e "of type cs.Out" in
                     write w "out ";
                     write w "out ";
                     expr_s w e
                     expr_s w e
                   | _ ->
                   | _ ->
@@ -1446,6 +1493,14 @@ let configure gen =
   Hashtbl.add gen.gspecial_vars "__as__" true;
   Hashtbl.add gen.gspecial_vars "__as__" true;
   Hashtbl.add gen.gspecial_vars "__cs__" true;
   Hashtbl.add gen.gspecial_vars "__cs__" true;
   
   
+  Hashtbl.add gen.gspecial_vars "__checked__" true;
+  Hashtbl.add gen.gspecial_vars "__lock__" true;
+  Hashtbl.add gen.gspecial_vars "__fixed__" true;
+  Hashtbl.add gen.gspecial_vars "__unsafe__" true;
+  Hashtbl.add gen.gspecial_vars "__addressOf__" true;
+  Hashtbl.add gen.gspecial_vars "__valueOf__" true;
+  Hashtbl.add gen.gspecial_vars "__sizeof__" true;
+  
   Hashtbl.add gen.gsupported_conversions (["haxe"; "lang"], "Null") (fun t1 t2 -> true);
   Hashtbl.add gen.gsupported_conversions (["haxe"; "lang"], "Null") (fun t1 t2 -> true);
   let last_needs_box = gen.gneeds_box in
   let last_needs_box = gen.gneeds_box in
   gen.gneeds_box <- (fun t -> match t with | TInst( { cl_path = (["haxe"; "lang"], "Null") }, _ ) -> true | _ -> last_needs_box t);
   gen.gneeds_box <- (fun t -> match t with | TInst( { cl_path = (["haxe"; "lang"], "Null") }, _ ) -> true | _ -> last_needs_box t);

+ 54 - 12
std/cs/Lib.hx

@@ -118,22 +118,54 @@ class Lib
 		return untyped Array.alloc(size);
 		return untyped Array.alloc(size);
 	}
 	}
 	
 	
+	/**
+		Creates a "checked" block, which throws exceptions for overflows.
+		
+		Usage:
+			cs.Lib.checked({
+				var x = 1000;
+				while(true)
+				{
+					x *= x;
+				}
+			});
+		This method only exists at compile-time, so it can't be called via reflection.
+	**/
+	@:extern public static inline function checked(block:Dynamic):Void
+	{
+		untyped __checked__(block);
+	}
+	
+	/**
+		Ensures that one thread does not enter a critical section of code while another thread
+		is in the critical section. If another thread attempts to enter a locked code, it 
+		will wait, block, until the object is released.
+		
+		This method only exists at compile-time, so it can't be called via reflection.
+	**/
+	@:extern public static inline function lock(obj:Dynamic, block:Dynamic):Void
+	{
+		untyped __lock__(obj, block);
+	}
 	
 	
 	//Unsafe code manipulation
 	//Unsafe code manipulation
 	#if unsafe
 	#if unsafe
 	/**
 	/**
 		Marks its parameters as fixed objects inside the defined block.
 		Marks its parameters as fixed objects inside the defined block.
+		The first variable declarations that use cs.Lib.pointerOfArray() will be the fixed definitions.
 		Usage:
 		Usage:
-			cs.Lib.fixed(obj1, obj2, obj3, 
-			{
-				//inside here obj1, obj2 and obj3 are fixed
+			cs.Lib.fixed({
+				var obj1 = cs.Lib.pointerOfArray(someArray);
+				var obj2 = cs.Lib.pointerOfArray(someArray2);
+				var obj3 = cs.Lib.pointerOfArray(someArray3);
+				//from now on, obj1, obj2 and obj3 are fixed
 			});
 			});
 		
 		
 		This method only exists at compile-time, so it can't be called via reflection.
 		This method only exists at compile-time, so it can't be called via reflection.
 	**/
 	**/
-	@:extern public static inline function fixed(?p1:Dynamic, ?p2:Dynamic, ?p3:Dynamic, ?p4:Dynamic, ?p5:Dynamic, ?p6:Dynamic, ?p7:Dynamic, ?p8:Dynamic, ?p9:Dynamic, ?p10:Dynamic):Void
+	@:extern public static inline function fixed(block:Dynamic):Void
 	{
 	{
-		untyped __fixed__(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
+		untyped __fixed__(block);
 	}
 	}
 	
 	
 	/**
 	/**
@@ -175,7 +207,7 @@ class Lib
 			cs.Lib.unsafe({
 			cs.Lib.unsafe({
 				var addr = cs.Lib.addressOf(x);
 				var addr = cs.Lib.addressOf(x);
 				trace(cs.Lib.valueOf(addr)); //0
 				trace(cs.Lib.valueOf(addr)); //0
-				x[0] = 42;
+				addr[0] = 42;
 				trace(cs.Lib.valueOf(addr)); //42
 				trace(cs.Lib.valueOf(addr)); //42
 			});
 			});
 			trace(x); //42
 			trace(x); //42
@@ -184,18 +216,20 @@ class Lib
 	**/
 	**/
 	@:extern public static inline function valueOf<T>(pointer:cs.Pointer<T>):T
 	@:extern public static inline function valueOf<T>(pointer:cs.Pointer<T>):T
 	{
 	{
-		return untyped __valueOf__(pointer, idx);
+		return untyped __valueOf__(pointer);
 	}
 	}
 	
 	
 	/**
 	/**
-		Transforms a managed native array into a Pointer.
+		Transforms a managed native array into a Pointer. Must be inside a fixed statement
 		Usage:
 		Usage:
 			var x:cs.NativeArray<Int> = new cs.NativeArray(1);
 			var x:cs.NativeArray<Int> = new cs.NativeArray(1);
 			cs.Lib.unsafe({
 			cs.Lib.unsafe({
-				var addr = cs.Lib.pointerOfArray(x);
-				trace(cs.Lib.valueOf(addr)); //0
-				x[0] = 42;
-				trace(cs.Lib.valueOf(addr)); //42
+				cs.Lib.fixed({
+					var addr = cs.Lib.pointerOfArray(x);
+					trace(cs.Lib.valueOf(addr)); //0
+					addr[0] = 42;
+					trace(cs.Lib.valueOf(addr)); //42
+				});
 			});
 			});
 			trace(x[0]); //42
 			trace(x[0]); //42
 		
 		
@@ -205,5 +239,13 @@ class Lib
 	{
 	{
 		return cast array;
 		return cast array;
 	}
 	}
+	
+	/**
+		Returns the byte size of the given struct. Only works with structs and basic types.
+	**/
+	@:extern public static inline function sizeof(struct:Class<Dynamic>):Int
+	{
+		return untyped __sizeof__(struct);
+	}
 	#end
 	#end
 }
 }

+ 6 - 6
tests/unit/TestCSharp.hx

@@ -36,9 +36,9 @@ class TestCSharp extends Test
 	@:unsafe public function testUnsafe()
 	@:unsafe public function testUnsafe()
 	{
 	{
 		var x:cs.NativeArray<Int> = new cs.NativeArray(10);
 		var x:cs.NativeArray<Int> = new cs.NativeArray(10);
-		var p;
-		cs.Lib.fixed(p = cs.Lib.pointerOfArray(x),
-		{
+		cs.Lib.fixed({
+			var p = cs.Lib.pointerOfArray(x);
+			var p = p;
 			for (i in 0...10)
 			for (i in 0...10)
 			{
 			{
 				p[0] = i;
 				p[0] = i;
@@ -46,8 +46,8 @@ class TestCSharp extends Test
 			}
 			}
 		});
 		});
 		
 		
-		cs.Lib.fixed(p = cs.Lib.pointerOfArray(x),
-		{
+		cs.Lib.fixed( {
+			var p = cs.Lib.pointerOfArray(x);
 			for (i in 0...10)
 			for (i in 0...10)
 			{
 			{
 				eq(p[i], i);
 				eq(p[i], i);
@@ -58,7 +58,7 @@ class TestCSharp extends Test
 		var addr = cs.Lib.addressOf(x);
 		var addr = cs.Lib.addressOf(x);
 		eq(cs.Lib.valueOf(addr), 0);
 		eq(cs.Lib.valueOf(addr), 0);
 		eq(addr[0], 0);
 		eq(addr[0], 0);
-		x[0] = 42;
+		addr[0] = 42;
 		eq(cs.Lib.valueOf(addr), 42);
 		eq(cs.Lib.valueOf(addr), 42);
 		eq(addr[0], 42);
 		eq(addr[0], 42);
 		eq(x, 42);
 		eq(x, 42);