diff options
Diffstat (limited to 'src/main/javassist/compiler/MemberResolver.java')
-rw-r--r-- | src/main/javassist/compiler/MemberResolver.java | 205 |
1 files changed, 123 insertions, 82 deletions
diff --git a/src/main/javassist/compiler/MemberResolver.java b/src/main/javassist/compiler/MemberResolver.java index fb2aa9b..00dac6c 100644 --- a/src/main/javassist/compiler/MemberResolver.java +++ b/src/main/javassist/compiler/MemberResolver.java @@ -1,11 +1,12 @@ /* * Javassist, a Java-bytecode translator toolkit. - * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. + * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. Alternatively, the contents of this file may be used under - * the terms of the GNU Lesser General Public License Version 2.1 or later. + * the terms of the GNU Lesser General Public License Version 2.1 or later, + * or the Apache License Version 2.0. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License @@ -15,11 +16,28 @@ package javassist.compiler; -import java.util.List; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.util.Hashtable; import java.util.Iterator; -import javassist.*; -import javassist.bytecode.*; -import javassist.compiler.ast.*; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; + +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtField; +import javassist.Modifier; +import javassist.NotFoundException; +import javassist.bytecode.AccessFlag; +import javassist.bytecode.ClassFile; +import javassist.bytecode.Descriptor; +import javassist.bytecode.MethodInfo; +import javassist.compiler.ast.ASTList; +import javassist.compiler.ast.ASTree; +import javassist.compiler.ast.Declarator; +import javassist.compiler.ast.Keyword; +import javassist.compiler.ast.Symbol; /* Code generator methods depending on javassist.* classes. */ @@ -36,22 +54,6 @@ public class MemberResolver implements TokenId { throw new CompileError("fatal"); } - /** - * @param jvmClassName a class name. Not a package name. - */ - public void recordPackage(String jvmClassName) { - String classname = jvmToJavaName(jvmClassName); - for (;;) { - int i = classname.lastIndexOf('.'); - if (i > 0) { - classname = classname.substring(0, i); - classPool.recordInvalidClassName(classname); - } - else - break; - } - } - public static class Method { public CtClass declaring; public MethodInfo info; @@ -88,8 +90,7 @@ public class MemberResolver implements TokenId { Method r = new Method(clazz, current, res); if (res == YES) return r; - else - maybe = r; + maybe = r; } } @@ -97,8 +98,7 @@ public class MemberResolver implements TokenId { argClassNames, maybe != null); if (m != null) return m; - else - return maybe; + return maybe; } private Method lookupMethod(CtClass clazz, String methodName, @@ -111,11 +111,10 @@ public class MemberResolver implements TokenId { // If the class is an array type, the class file is null. // If so, search the super class java.lang.Object for clone() etc. if (cf != null) { - List list = cf.getMethods(); - int n = list.size(); - for (int i = 0; i < n; ++i) { - MethodInfo minfo = (MethodInfo)list.get(i); - if (minfo.getName().equals(methodName)) { + List<MethodInfo> list = cf.getMethods(); + for (MethodInfo minfo:list) { + if (minfo.getName().equals(methodName) + && (minfo.getAccessFlags() & AccessFlag.BRIDGE) == 0) { int res = compareSignature(minfo.getDescriptor(), argTypes, argDims, argClassNames); if (res != NO) { @@ -132,7 +131,8 @@ public class MemberResolver implements TokenId { if (onlyExact) maybe = null; else - onlyExact = maybe != null; + if (maybe != null) + return maybe; int mod = clazz.getModifiers(); boolean isIntf = Modifier.isInterface(mod); @@ -150,30 +150,28 @@ public class MemberResolver implements TokenId { } catch (NotFoundException e) {} - if (isIntf || Modifier.isAbstract(mod)) - try { - CtClass[] ifs = clazz.getInterfaces(); - int size = ifs.length; - for (int i = 0; i < size; ++i) { - Method r = lookupMethod(ifs[i], methodName, - argTypes, argDims, argClassNames, - onlyExact); + try { + CtClass[] ifs = clazz.getInterfaces(); + for (CtClass intf:ifs) { + Method r = lookupMethod(intf, methodName, + argTypes, argDims, argClassNames, + onlyExact); + if (r != null) + return r; + } + + if (isIntf) { + // finally search java.lang.Object. + CtClass pclazz = clazz.getSuperclass(); + if (pclazz != null) { + Method r = lookupMethod(pclazz, methodName, argTypes, + argDims, argClassNames, onlyExact); if (r != null) return r; } - - if (isIntf) { - // finally search java.lang.Object. - CtClass pclazz = clazz.getSuperclass(); - if (pclazz != null) { - Method r = lookupMethod(pclazz, methodName, argTypes, - argDims, argClassNames, onlyExact); - if (r != null) - return r; - } - } } - catch (NotFoundException e) {} + } + catch (NotFoundException e) {} return maybe; } @@ -275,6 +273,7 @@ public class MemberResolver implements TokenId { * Only used by fieldAccess() in MemberCodeGen and TypeChecker. * * @param jvmClassName a JVM class name. e.g. java/lang/String + * @see #lookupClass(String, boolean) */ public CtField lookupFieldByJvmName2(String jvmClassName, Symbol fieldSym, ASTree expr) throws NoFieldException @@ -309,7 +308,7 @@ public class MemberResolver implements TokenId { } /** - * @param name a qualified class name. e.g. java.lang.String + * @param className a qualified class name. e.g. java.lang.String */ public CtField lookupField(String className, Symbol fieldName) throws CompileError @@ -336,7 +335,7 @@ public class MemberResolver implements TokenId { } /** - * @parma classname jvm class name. + * @param classname jvm class name. */ public CtClass lookupClass(int type, int dim, String classname) throws CompileError @@ -405,45 +404,78 @@ public class MemberResolver implements TokenId { public CtClass lookupClass(String name, boolean notCheckInner) throws CompileError { + Map<String,String> cache = getInvalidNames(); + String found = cache.get(name); + if (found == INVALID) + throw new CompileError("no such class: " + name); + else if (found != null) + try { + return classPool.get(found); + } + catch (NotFoundException e) {} + + CtClass cc = null; try { - return lookupClass0(name, notCheckInner); + cc = lookupClass0(name, notCheckInner); } catch (NotFoundException e) { - return searchImports(name); + cc = searchImports(name); + } + + cache.put(name, cc.getName()); + return cc; + } + + private static final String INVALID = "<invalid>"; + private static Map<ClassPool, Reference<Map<String,String>>> invalidNamesMap = + new WeakHashMap<ClassPool, Reference<Map<String,String>>>(); + private Map<String,String> invalidNames = null; + + // for unit tests + public static int getInvalidMapSize() { return invalidNamesMap.size(); } + + private Map<String,String> getInvalidNames() { + Map<String,String> ht = invalidNames; + if (ht == null) { + synchronized (MemberResolver.class) { + Reference<Map<String,String>> ref = invalidNamesMap.get(classPool); + if (ref != null) + ht = ref.get(); + + if (ht == null) { + ht = new Hashtable<String,String>(); + invalidNamesMap.put(classPool, new WeakReference<Map<String,String>>(ht)); + } + } + + invalidNames = ht; } + + return ht; } private CtClass searchImports(String orgName) throws CompileError { if (orgName.indexOf('.') < 0) { - Iterator it = classPool.getImportedPackages(); + Iterator<String> it = classPool.getImportedPackages(); while (it.hasNext()) { - String pac = (String)it.next(); - String fqName = pac + '.' + orgName; + String pac = it.next(); + String fqName = pac.replaceAll("\\.$","") + "." + orgName; try { - CtClass cc = classPool.get(fqName); - // if the class is found, - classPool.recordInvalidClassName(orgName); - return cc; + return classPool.get(fqName); } catch (NotFoundException e) { - classPool.recordInvalidClassName(fqName); try { - if (pac.endsWith("." + orgName)) { - CtClass cc = classPool.get(pac); - // if the class is found, - classPool.recordInvalidClassName(orgName); - return cc; - } - } - catch (NotFoundException e2) { - classPool.recordInvalidClassName(pac); + if (pac.endsWith("." + orgName)) + return classPool.get(pac); } + catch (NotFoundException e2) {} } } } + getInvalidNames().put(orgName, INVALID); throw new CompileError("no such class: " + orgName); } @@ -459,11 +491,9 @@ public class MemberResolver implements TokenId { int i = classname.lastIndexOf('.'); if (notCheckInner || i < 0) throw e; - else { - StringBuffer sbuf = new StringBuffer(classname); - sbuf.setCharAt(i, '$'); - classname = sbuf.toString(); - } + StringBuffer sbuf = new StringBuffer(classname); + sbuf.setCharAt(i, '$'); + classname = sbuf.toString(); } } while (cc == null); return cc; @@ -477,8 +507,7 @@ public class MemberResolver implements TokenId { public String resolveClassName(ASTList name) throws CompileError { if (name == null) return null; - else - return javaToJvmName(lookupClassByName(name).getName()); + return javaToJvmName(lookupClassByName(name).getName()); } /* Expands a simple class name to java.lang.*. @@ -487,8 +516,7 @@ public class MemberResolver implements TokenId { public String resolveJvmClassName(String jvmName) throws CompileError { if (jvmName == null) return null; - else - return javaToJvmName(lookupClassByJvmName(jvmName).getName()); + return javaToJvmName(lookupClassByJvmName(jvmName).getName()); } public static CtClass getSuperclass(CtClass c) throws CompileError { @@ -502,6 +530,19 @@ public class MemberResolver implements TokenId { + c.getName()); } + public static CtClass getSuperInterface(CtClass c, String interfaceName) + throws CompileError + { + try { + CtClass[] intfs = c.getInterfaces(); + for (int i = 0; i < intfs.length; i++) + if (intfs[i].getName().equals(interfaceName)) + return intfs[i]; + } catch (NotFoundException e) {} + throw new CompileError("cannot find the super inetrface " + interfaceName + + " of " + c.getName()); + } + public static String javaToJvmName(String classname) { return classname.replace('.', '/'); } |