FUBAR in java.io.PrintWriter.h due to bridge methods

Tom Tromey tromey@redhat.com
Wed Apr 18 00:34:00 GMT 2007


Tom> I think the only fix is to further mangle subsequent bridge
Tom> methods. How unpleasant.
Here's one patch. I am still testing it.
This changes our mangling so that a "bridge target" is named after its
declaring class. This is not completely robust -- I picked the
unqualified class name for brevity, but this can yield incorrect
results if there are classes with the same name, in different
packages, that have an inheritance relationship.
I think we can't really faithfully represent JVM programs in C++
headers. For the full solution we would probably have to mangle every
method name with a fully qualified class name.
This sort of approach represents a tradeoff that is "good enough" for
libgcj. Though of course that's what we thought the last time around.
Tom
Index: classpath/tools/gnu/classpath/tools/javah/ClassWrapper.java
===================================================================
--- classpath/tools/gnu/classpath/tools/javah/ClassWrapper.java	(revision 123877)
+++ classpath/tools/gnu/classpath/tools/javah/ClassWrapper.java	(working copy)
@@ -1,5 +1,5 @@
 /* ClassWrapper.java - wrap ASM class objects
- Copyright (C) 2006 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -43,6 +43,7 @@
 import java.io.PrintStream;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 
@@ -68,6 +69,11 @@
 // A set of all the method names in this class.
 HashSet methodNames = new HashSet();
 
+ // This maps a method name + descriptor, e.g. "method()V", to the
+ // name chosen for the method. This is used when computing the
+ // names of bridge method targets.
+ HashMap methodNameMap = new HashMap();
+
 public ClassWrapper(Main classpath)
 {
 this.classpath = classpath;
@@ -187,18 +193,24 @@
 superClass.makeVtable();
 vtable = new ArrayList(superClass.vtable);
 bridgeTargets = new HashSet(superClass.bridgeTargets);
+	methodNameMap = new HashMap(superClass.methodNameMap);
 }
 else
 {
 // Object.
 vtable = new ArrayList();
 bridgeTargets = new HashSet();
+	methodNameMap = new HashMap();
 }
 addLocalMethods();
 addInterfaces(this);
 
- // Make a set of all the targets of bridge methods.
- // We rename bridge methods to avoid problems with C++.
+ // Make a set of all the targets of bridge methods. We rename
+ // bridge target methods to avoid problems with C++. You might
+ // think we could rename the bridge methods themselves, but bridge
+ // methods by definition override a method from the superclass --
+ // and we have to consider the superclass' header as an
+ // unchangeable entity.
 Iterator i = methods.iterator();
 while (i.hasNext())
 {
@@ -232,8 +244,23 @@
 while (i.hasNext())
 {
 MethodNode m = (MethodNode) i.next();
- boolean isTarget = bridgeTargets.contains(m.name + m.desc);
- MethodHelper.print(out, m, this, isTarget);
+	String nameToUse = m.name;
+	String sum = m.name + m.desc;
+	if (bridgeTargets.contains(sum))
+	 {
+	 if (methodNameMap.containsKey(sum))
+	 nameToUse = (String) methodNameMap.get(sum);
+	 else
+	 {
+		// Bridget target that is new in this class.
+		String cname = this.name;
+		int index = cname.lastIndexOf('/');
+		cname = cname.substring(index + 1);
+		nameToUse = cname + "$" + nameToUse;
+	 }
+	 }
+	methodNameMap.put(sum, nameToUse);
+ MethodHelper.print(out, m, this, nameToUse);
 }
 }
 
Index: classpath/tools/gnu/classpath/tools/javah/MethodHelper.java
===================================================================
--- classpath/tools/gnu/classpath/tools/javah/MethodHelper.java	(revision 123877)
+++ classpath/tools/gnu/classpath/tools/javah/MethodHelper.java	(working copy)
@@ -1,5 +1,5 @@
 /* MethodHelper.java - helper class for manipulating methods
- Copyright (C) 2006 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -76,7 +76,7 @@
 }
 
 public static void print(CniPrintStream out, MethodNode meth,
- ClassWrapper declarer, boolean isBridgeTarget)
+ ClassWrapper declarer, String realMethodName)
 {
 if ("<clinit>".equals(meth.name))
 return;
@@ -97,15 +97,7 @@
 {
 out.print(Type.getReturnType(meth.desc));
 out.print(" ");
- if (isBridgeTarget)
- {
- out.print("target$");
- out.print(meth.name);
- }
- else
- {
- out.print(Keywords.getCxxName(meth.name));
- }
+	out.print(realMethodName);
 }
 else
 {


More information about the Java mailing list

AltStyle によって変換されたページ (->オリジナル) /