Browse Source

[java/cs] Native reflection for haxe classes that extend native classes. Fixed issue #822

Caue Waneck 13 years ago
parent
commit
ac8182038f
8 changed files with 129 additions and 15 deletions
  1. 25 6
      gencommon.ml
  2. 6 1
      gencs.ml
  3. 6 1
      genjava.ml
  4. 2 2
      std/haxe/Resource.hx
  5. 0 5
      std/java/lang/Throwable.hx
  6. 3 0
      tests/unit/Test.hx
  7. 41 0
      tests/unit/TestCSharp.hx
  8. 46 0
      tests/unit/TestJava.hx

+ 25 - 6
gencommon.ml

@@ -7075,7 +7075,7 @@ struct
     
     if is_override cl then cl.cl_overrides <- get_cl.cf_name :: cl.cl_overrides
   
-  let implement_invokeField ctx cl =
+  let implement_invokeField ctx ~slow_invoke cl =
     (* 
       There are two ways to implement an haxe reflection-enabled class:
       When we extend a non-hxgen class, and when we extend the base HxObject class.
@@ -7147,7 +7147,7 @@ struct
     
     let dyn_fun = mk_class_field (ctx.rcf_gen.gmk_internal_name "hx" "invokeField") fun_t false cl.cl_pos (Method MethNormal) [] in
     
-    let mk_switch_dyn cfs static = 
+    let mk_switch_dyn cfs static old = 
       (* mk_class_field name t public pos kind params = *)
       
       let get_case (names,cf) =
@@ -7173,6 +7173,13 @@ struct
       in
       
       let cases = List.map get_case cfs in
+      let cases = match old with
+        | [] -> cases
+        | _ -> 
+          let ncases = List.map (fun cf -> switch_case ctx pos cf.cf_name) old in
+          ( ncases, mk_return ((get slow_invoke) this (mk_local (fst (List.hd field_args)) pos) (mk_local dynamic_arg pos)) ) :: cases
+      in
+      
       let default = if !is_override && not(static) then 
         (* let call_super ctx fn_args ret_t fn_name this_t pos = *)
         { eexpr = TReturn(Some (call_super ctx all_args t_dynamic dyn_fun.cf_name this_t pos) ); etype = basic.tvoid; epos = pos }
@@ -7207,13 +7214,25 @@ struct
       let statics = collect_fields cl (Some true) (Some true) in
       let nonstatics = collect_fields cl (Some true) (Some false) in
       
+      let old_nonstatics = ref [] in
+      
+      let nonstatics = match slow_invoke with
+        | None -> nonstatics
+        | Some _ ->
+          List.filter (fun (n,cf) ->
+            let is_old = not (PMap.mem cf.cf_name cl.cl_fields) || List.mem cf.cf_name cl.cl_overrides in
+            (if is_old then old_nonstatics := cf :: !old_nonstatics);
+            not is_old
+          ) nonstatics
+      in
+      
       if ctx.rcf_handle_statics then 
       {
-        eexpr = TIf(mk_local is_static pos, mk_switch_dyn statics true, Some(mk_switch_dyn nonstatics false));
+        eexpr = TIf(mk_local is_static pos, mk_switch_dyn statics true [], Some(mk_switch_dyn nonstatics false !old_nonstatics));
         etype = basic.tvoid;
         epos = pos;
       } else
-        mk_switch_dyn nonstatics false
+        mk_switch_dyn nonstatics false !old_nonstatics
     in
     
     dyn_fun.cf_expr <- Some 
@@ -7556,13 +7575,13 @@ struct
   *)
   let priority = solve_deps name [DAfter UniversalBaseClass.priority]
   
-  let configure ctx =
+  let configure ?slow_invoke ctx =
     let gen = ctx.rcf_gen in
     let run = (fun md -> match md with
       | TClassDecl cl when is_hxgen md && ( not cl.cl_interface || has_meta ":$baseinterface" cl.cl_meta ) ->
         (if has_meta ":replaceReflection" cl.cl_meta then replace_reflection ctx cl);
         (if not (PMap.mem (gen.gmk_internal_name "hx" "getField") cl.cl_fields) then implement_get_set ctx cl);
-        (if not (PMap.mem (gen.gmk_internal_name "hx" "invokeField") cl.cl_fields) then implement_invokeField ctx cl);
+        (if not (PMap.mem (gen.gmk_internal_name "hx" "invokeField") cl.cl_fields) then implement_invokeField ctx ~slow_invoke:slow_invoke cl);
         (implement_dynamics ctx cl);
         (if not (PMap.mem (gen.gmk_internal_name "hx" "lookupField") cl.cl_fields) then implement_final_lookup ctx cl);
         (if not (PMap.mem (gen.gmk_internal_name "hx" "classFields") cl.cl_fields) then implement_fields ctx cl);

+ 6 - 1
gencs.ml

@@ -1680,7 +1680,12 @@ let configure gen =
   
   ReflectionCFs.implement_varargs_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"], "VarArgsBase")) );
   
-  ReflectionCFs.configure rcf_ctx;
+  let slow_invoke = mk_static_field_access_infer (runtime_cl) "slowCallField" Ast.null_pos [] in
+  ReflectionCFs.configure rcf_ctx ~slow_invoke:(fun ethis efield eargs -> {
+    eexpr = TCall(slow_invoke, [ethis; efield; eargs]);
+    etype = t_dynamic;
+    epos = ethis.epos;
+  } );
   
   let objdecl_fn = ReflectionCFs.implement_dynamic_object_ctor rcf_ctx dynamic_object in
   

+ 6 - 1
genjava.ml

@@ -1576,7 +1576,12 @@ let configure gen =
   
   ReflectionCFs.implement_varargs_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"], "VarArgsBase")) );
   
-  ReflectionCFs.configure rcf_ctx;
+  let slow_invoke = mk_static_field_access_infer (runtime_cl) "slowCallField" Ast.null_pos [] in
+  ReflectionCFs.configure rcf_ctx ~slow_invoke:(fun ethis efield eargs -> {
+    eexpr = TCall(slow_invoke, [ethis; efield; eargs]);
+    etype = t_dynamic;
+    epos = ethis.epos;
+  } );
   
   let objdecl_fn = ReflectionCFs.implement_dynamic_object_ctor rcf_ctx dynamic_object in
   

+ 2 - 2
std/haxe/Resource.hx

@@ -66,7 +66,7 @@ class Resource {
 
 	public static function getString( name : String ) : String {
 		#if java
-		var stream = java.Lib.toNativeType(Resource).getResourceAsStream("/" + name);
+		var stream = cast(Resource, java.lang.Class<Dynamic>).getResourceAsStream("/" + name);
 		if (stream == null)
 			return null;
 		var stream = new java.io.NativeInput(stream);
@@ -93,7 +93,7 @@ class Resource {
 
 	public static function getBytes( name : String ) : haxe.io.Bytes {
 		#if java
-		var stream = java.Lib.toNativeType(Resource).getResourceAsStream("/" + name);
+		var stream = cast(Resource, java.lang.Class<Dynamic>).getResourceAsStream("/" + name);
 		if (stream == null)
 			return null;
 		var stream = new java.io.NativeInput(stream);

+ 0 - 5
std/java/lang/Throwable.hx

@@ -1,11 +1,6 @@
 package java.lang;
 import java.NativeArray;
 
-/**
- * ...
- * @author waneck
- */
-
 extern class Throwable 
 {
 	

+ 3 - 0
tests/unit/Test.hx

@@ -202,6 +202,9 @@ package unit;
 			#if cs
 			new TestCSharp(),
 			#end
+			#if java
+			new TestJava(),
+			#end
 			//new TestUnspecified(),
 			//new TestRemoting(),
 		];

+ 41 - 0
tests/unit/TestCSharp.hx

@@ -22,6 +22,10 @@ class TestCSharp extends Test
 		var i = 10;
 		refTest(i);
 		eq(i, 20);
+		
+		var cl = new HxClass();
+		cl.refTest(i);
+		eq(i, 80);
 	}
 	
 	public function testOut()
@@ -29,6 +33,10 @@ class TestCSharp extends Test
 		var i = 0;
 		outTest(i, 10);
 		eq(i, 20);
+		
+		var cl = new HxClass();
+		cl.outTest(i, 10);
+		eq(i, 40);
 	}
 	
 	public function testChecked()
@@ -82,4 +90,37 @@ class TestCSharp extends Test
 	#end
 	
 	#end
+}
+
+@:nativegen private class NativeClass
+{
+	public function outTest(out:cs.Out<Int>, x:Int):Void
+	{
+		out = x * 2;
+	}
+	
+	public function refTest(i:cs.Ref<Int>):Void
+	{
+		i *= 2;
+	}
+}
+
+private class HxClass extends NativeClass
+{
+	public function new()
+	{
+		
+	}
+	
+	//here it would normally fail due to the added fast reflection field
+	override public function outTest(out:cs.Out<Int>, x:Int):Void 
+	{
+		out = x * 4;
+	}
+	
+	override public function refTest(i:cs.Ref<Int>):Void 
+	{
+		super.refTest(i);
+		i *= 2;
+	}
 }

+ 46 - 0
tests/unit/TestJava.hx

@@ -0,0 +1,46 @@
+package unit;
+
+class TestJava extends Test
+{
+	#if java
+	
+	function textException()
+	{
+		var native = new NativeClass();
+		var hx:NativeClass = new HxClass();
+		
+		exc(function() try native.excTest() catch (e:Dynamic) throw e);
+		var dyn:Dynamic = native;
+		exc(dyn.excTest);
+		
+		try 
+			hx.excTest()
+		catch(e:Dynamic) throw e; //shouldn't throw any exception
+	}
+	
+	#end
+}
+
+@:nativegen private class NativeClass
+{
+	public function new()
+	{
+		
+	}
+	
+	@:throws("java.lang.Throwable")
+	public function excTest():Void
+	{
+		throw new java.lang.Throwable("test", null);
+	}
+}
+
+private class HxClass extends NativeClass
+{
+	
+	@:throws("java.lang.Throwable")
+	override public function excTest():Void 
+	{
+		
+	}
+}