소스 검색

[jvm] dig up local names from LocalVariableTable

closes #9528
Simon Krajewski 5 년 전
부모
커밋
21cf1eb4a6
3개의 변경된 파일71개의 추가작업 그리고 5개의 파일을 삭제
  1. 11 2
      libs/javalib/jData.ml
  2. 30 2
      libs/javalib/jReader.ml
  3. 30 1
      src/codegen/java.ml

+ 11 - 2
libs/javalib/jData.ml

@@ -92,8 +92,6 @@ type jconstant =
   | ConstInvokeDynamic of (bootstrap_method * unqualified_name * jsignature) (* tag = 18 *)
   | ConstUnusable
 
-type jcode = unit (* TODO *)
-
 type jaccess_flag =
   | JPublic (* 0x0001 *)
   | JPrivate (* 0x0002 *)
@@ -135,12 +133,23 @@ and jannotation_value =
   | ValAnnotation of jannotation (* @ *)
   | ValArray of jannotation_value list (* [ *)
 
+type jlocal = {
+	ld_start_pc : int;
+	ld_length : int;
+	ld_name : string;
+	ld_descriptor : string;
+	ld_index : int;
+}
+
 type jattribute =
   | AttrDeprecated
   | AttrVisibleAnnotations of jannotation list
   | AttrInvisibleAnnotations of jannotation list
+  | AttrLocalVariableTable of jlocal list
   | AttrUnknown of string * string
 
+type jcode = jattribute list (* TODO *)
+
 type jfield_kind =
   | JKField
   | JKMethod

+ 30 - 2
libs/javalib/jReader.ml

@@ -416,6 +416,23 @@ let parse_attribute on_special consts ch =
   | "Deprecated" ->
     if alen <> 0 then error();
     Some (AttrDeprecated)
+  | "LocalVariableTable" ->
+	let len = read_ui16 ch in
+	let locals = List.init len (fun _ ->
+		let start_pc = read_ui16 ch in
+		let length = read_ui16 ch in
+		let name = get_string consts ch in
+		let descriptor = get_string consts ch in
+		let index = read_ui16 ch in
+		{
+			ld_start_pc = start_pc;
+			ld_length = length;
+			ld_name = name;
+			ld_descriptor = descriptor;
+			ld_index = index
+		}
+	) in
+	Some (AttrLocalVariableTable locals)
   | "RuntimeVisibleAnnotations" ->
     let anncount = read_ui16 ch in
     Some (AttrVisibleAnnotations (List.init anncount (fun _ -> parse_annotation consts ch)))
@@ -469,8 +486,19 @@ let parse_field kind consts ch =
       let s = get_string consts ch in
       jsig := parse_signature s;
       None
-    | JKMethod, "Code" -> (* TODO *)
-      do_default()
+    | JKMethod, "Code" ->
+	  ignore(read_ui16 ch); (* max stack *)
+	  ignore(read_ui16 ch); (* max locals *)
+	  let len = read_i32 ch in
+	  ignore(IO.nread_string ch len); (* code *)
+	  let len = read_ui16 ch in
+	  for i = 0 to len - 1 do
+	  	ignore(IO.nread_string ch 8);
+	  done; (* exceptions *)
+      let attrib_count = read_ui16 ch in
+	  let attribs = parse_attributes consts ch attrib_count in
+	  code := Some attribs;
+	  None
     | JKMethod, "Exceptions" ->
       let num = read_ui16 ch in
       throws := List.init num (fun _ -> TObject(get_class consts ch,[]));

+ 30 - 1
src/codegen/java.ml

@@ -307,6 +307,34 @@ let convert_java_enum ctx p pe =
 				| _ -> ()
 		) field.jf_throws;
 
+		let extract_local_names () =
+			let default i =
+				"param" ^ string_of_int i
+			in
+			match field.jf_code with
+			| None ->
+				default
+			| Some attribs -> try
+				let rec loop attribs = match attribs with
+					| AttrLocalVariableTable locals :: _ ->
+						locals
+					| _ :: attribs ->
+						loop attribs
+					| [] ->
+						raise Not_found
+				in
+				let locals = loop attribs in
+				let h = Hashtbl.create 0 in
+				List.iter (fun local ->
+					Hashtbl.replace h local.ld_index local.ld_name
+				) locals;
+				(fun i ->
+					try Hashtbl.find h (i - 1) (* they are 1-based *)
+					with Not_found -> "param" ^ string_of_int i
+				)
+			with Not_found ->
+				default
+		in
 		let kind = match field.jf_kind with
 			| JKField when !readonly ->
 				FProp (("default",null_pos), ("null",null_pos), Some (convert_signature ctx p field.jf_signature,null_pos), None)
@@ -315,6 +343,7 @@ let convert_java_enum ctx p pe =
 			| JKMethod ->
 				match field.jf_signature with
 				| TMethod (args, ret) ->
+					let local_names = extract_local_names() in
 					let old_types = ctx.jtparams in
 					(match ctx.jtparams with
 					| c :: others -> ctx.jtparams <- (c @ field.jf_types) :: others
@@ -322,7 +351,7 @@ let convert_java_enum ctx p pe =
 					let i = ref 0 in
 					let args = List.map (fun s ->
 						incr i;
-						("param" ^ string_of_int !i,null_pos), false, [], Some(convert_signature ctx p s,null_pos), None
+						(local_names !i,null_pos), false, [], Some(convert_signature ctx p s,null_pos), None
 					) args in
 					let t = Option.map_default (convert_signature ctx p) (mk_type_path ctx ([], "Void") []) ret in
 					cff_meta := (Meta.Overload, [], p) :: !cff_meta;