Browse Source

[jvm] consider field closures on dynamic access, but don't generate classes for them

Simon Krajewski 5 years ago
parent
commit
17fdbb581b
2 changed files with 28 additions and 7 deletions
  1. 11 7
      src/generators/genjvm.ml
  2. 17 0
      std/jvm/Jvm.hx

+ 11 - 7
src/generators/genjvm.ml

@@ -2120,15 +2120,19 @@ let generate_dynamic_access gctx (jc : JvmClass.builder) fields is_anon =
 		let jm = jc#spawn_method "_hx_getField" jsig [MPublic;MSynthetic] in
 		let _,load,_ = jm#add_local "name" string_sig VarArgument in
 		jm#finalize_arguments;
-		let fields = List.filter (fun (_,_,kind) -> match kind with
-			| Method (MethNormal | MethInline) -> false
-			| _ -> true
-		) fields in
 		let cases = List.map (fun (name,jsig,kind) ->
 			[name],(fun () ->
-				jm#load_this;
-				jm#getfield jc#get_this_path name jsig;
-				jm#expect_reference_type;
+			begin match kind,jsig with
+					| Method (MethNormal | MethInline),TMethod(args,_) ->
+						jm#load_this;
+						jm#string name;
+						jm#new_native_array java_class_sig (List.map (fun jsig -> fun () -> jm#get_class jsig) args);
+						jm#invokestatic haxe_jvm_path "readFieldClosure" (method_sig [object_sig;string_sig;array_sig (java_class_sig)] (Some (object_sig)))
+					| _ ->
+						jm#load_this;
+						jm#getfield jc#get_this_path name jsig;
+						jm#expect_reference_type;
+				end;
 				ignore(jm#get_code#get_stack#pop);
 				jm#get_code#get_stack#push object_sig;
 			)

+ 17 - 0
std/jvm/Jvm.hx

@@ -280,6 +280,23 @@ class Jvm {
 		throw 'Cannot array-write on $obj';
 	}
 
+	static public function readFieldClosure(obj:Dynamic, name:String, parameterTypes:NativeArray<java.lang.Class<Dynamic>>):Dynamic {
+		var cl = (obj : java.lang.Object).getClass();
+		var method = cl.getMethod(name, parameterTypes);
+		if (method.isBridge()) {
+			/* This is probably not what we want... go through all methods and see if we find one that
+				isn't a bridge. This is pretty awkward, but I can't figure out how to use the Java reflection
+				API properly. */
+			for (meth in cl.getMethods()) {
+				if (meth.getName() == name && !meth.isBridge() && method.getParameterCount() == parameterTypes.length) {
+					method = meth;
+					break;
+				}
+			}
+		}
+		return new jvm.Closure(obj, method);
+	}
+
 	static public function readFieldNoObject(obj:Dynamic, name:String):Dynamic {
 		var isStatic = instanceof(obj, java.lang.Class);
 		var cl = isStatic ? obj : (obj : java.lang.Object).getClass();