diff options
author | chibash <chiba@javassist.org> | 2014-11-23 01:08:22 +0900 |
---|---|---|
committer | chibash <chiba@javassist.org> | 2014-11-23 01:08:22 +0900 |
commit | f2093c28be24336593e1ebd9c2c633ee0f8c5b5c (patch) | |
tree | a143744ccbf9c43fa70e88940f36f96136870e79 /src/main | |
parent | e000e8f682a284b7b5d0c03ca32866e745045fa0 (diff) | |
download | javassist-f2093c28be24336593e1ebd9c2c633ee0f8c5b5c.tar.gz javassist-f2093c28be24336593e1ebd9c2c633ee0f8c5b5c.zip |
fiexed JASSIST-238
Diffstat (limited to 'src/main')
-rw-r--r-- | src/main/javassist/bytecode/Bytecode.java | 37 | ||||
-rw-r--r-- | src/main/javassist/compiler/MemberCodeGen.java | 58 | ||||
-rw-r--r-- | src/main/javassist/compiler/MemberResolver.java | 14 | ||||
-rw-r--r-- | src/main/javassist/compiler/Parser.java | 6 | ||||
-rw-r--r-- | src/main/javassist/compiler/TypeChecker.java | 68 |
5 files changed, 133 insertions, 50 deletions
diff --git a/src/main/javassist/bytecode/Bytecode.java b/src/main/javassist/bytecode/Bytecode.java index fb4d3ec9..051619d1 100644 --- a/src/main/javassist/bytecode/Bytecode.java +++ b/src/main/javassist/bytecode/Bytecode.java @@ -924,11 +924,14 @@ public class Bytecode extends ByteVector implements Cloneable, Opcode { * @see Descriptor#ofConstructor(CtClass[]) */ public void addInvokespecial(CtClass clazz, String name, String desc) { - addInvokespecial(constPool.addClassInfo(clazz), name, desc); + boolean isInterface = clazz == null ? false : clazz.isInterface(); + addInvokespecial(isInterface, + constPool.addClassInfo(clazz), name, desc); } /** - * Appends INVOKESPECIAL. + * Appends INVOKESPECIAL. The invoked method must not be a default + * method declared in an interface. * * @param clazz the fully-qualified class name. * @param name the method name @@ -938,11 +941,12 @@ public class Bytecode extends ByteVector implements Cloneable, Opcode { * @see Descriptor#ofConstructor(CtClass[]) */ public void addInvokespecial(String clazz, String name, String desc) { - addInvokespecial(constPool.addClassInfo(clazz), name, desc); + addInvokespecial(false, constPool.addClassInfo(clazz), name, desc); } /** - * Appends INVOKESPECIAL. + * Appends INVOKESPECIAL. The invoked method must not be a default + * method declared in an interface. * * @param clazz the index of <code>CONSTANT_Class_info</code> * structure. @@ -953,8 +957,31 @@ public class Bytecode extends ByteVector implements Cloneable, Opcode { * @see Descriptor#ofConstructor(CtClass[]) */ public void addInvokespecial(int clazz, String name, String desc) { + addInvokespecial(false, clazz, name, desc); + } + + /** + * Appends INVOKESPECIAL. + * + * @param isInterface true if the invoked method is a default method + * declared in an interface. + * @param clazz the index of <code>CONSTANT_Class_info</code> + * structure. + * @param name the method name + * @param desc the descriptor of the method signature. + * + * @see Descriptor#ofMethod(CtClass,CtClass[]) + * @see Descriptor#ofConstructor(CtClass[]) + */ + public void addInvokespecial(boolean isInterface, int clazz, String name, String desc) { add(INVOKESPECIAL); - addIndex(constPool.addMethodrefInfo(clazz, name, desc)); + int index; + if (isInterface) + index = constPool.addInterfaceMethodrefInfo(clazz, name, desc); + else + index = constPool.addMethodrefInfo(clazz, name, desc); + + addIndex(index); growStack(Descriptor.dataSize(desc) - 1); } diff --git a/src/main/javassist/compiler/MemberCodeGen.java b/src/main/javassist/compiler/MemberCodeGen.java index 167e4ccc..f799eea0 100644 --- a/src/main/javassist/compiler/MemberCodeGen.java +++ b/src/main/javassist/compiler/MemberCodeGen.java @@ -489,30 +489,44 @@ public class MemberCodeGen extends CodeGen { } else if (op == '.') { ASTree target = e.oprand1(); - if (target instanceof Keyword) - if (((Keyword)target).get() == SUPER) - isSpecial = true; - - try { - target.accept(this); + String classFollowedByDotSuper = TypeChecker.isDotSuper(target); + if (classFollowedByDotSuper != null) { + isSpecial = true; + targetClass = MemberResolver.getSuperInterface(thisClass, + classFollowedByDotSuper); + if (inStaticMethod || (cached != null && cached.isStatic())) + isStatic = true; // should be static + else { + aload0pos = bytecode.currentPc(); + bytecode.addAload(0); // this + } } - catch (NoFieldException nfe) { - if (nfe.getExpr() != target) - throw nfe; - - // it should be a static method. - exprType = CLASS; - arrayDim = 0; - className = nfe.getField(); // JVM-internal - isStatic = true; + else { + if (target instanceof Keyword) + if (((Keyword)target).get() == SUPER) + isSpecial = true; + + try { + target.accept(this); + } + catch (NoFieldException nfe) { + if (nfe.getExpr() != target) + throw nfe; + + // it should be a static method. + exprType = CLASS; + arrayDim = 0; + className = nfe.getField(); // JVM-internal + isStatic = true; + } + + if (arrayDim > 0) + targetClass = resolver.lookupClass(javaLangObject, true); + else if (exprType == CLASS /* && arrayDim == 0 */) + targetClass = resolver.lookupClassByJvmName(className); + else + badMethod(); } - - if (arrayDim > 0) - targetClass = resolver.lookupClass(javaLangObject, true); - else if (exprType == CLASS /* && arrayDim == 0 */) - targetClass = resolver.lookupClassByJvmName(className); - else - badMethod(); } else badMethod(); diff --git a/src/main/javassist/compiler/MemberResolver.java b/src/main/javassist/compiler/MemberResolver.java index f304b034..8f7591cf 100644 --- a/src/main/javassist/compiler/MemberResolver.java +++ b/src/main/javassist/compiler/MemberResolver.java @@ -21,6 +21,7 @@ import java.lang.ref.WeakReference; import java.util.WeakHashMap; import java.util.List; import java.util.Iterator; + import javassist.*; import javassist.bytecode.*; import javassist.compiler.ast.*; @@ -523,6 +524,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('.', '/'); } diff --git a/src/main/javassist/compiler/Parser.java b/src/main/javassist/compiler/Parser.java index 05b33184..2a1d5d63 100644 --- a/src/main/javassist/compiler/Parser.java +++ b/src/main/javassist/compiler/Parser.java @@ -1001,6 +1001,7 @@ public final class Parser implements TokenId { * | postfix.expr "." Identifier * | postfix.expr ( "[" "]" )* "." CLASS * | postfix.expr "#" Identifier + * | postfix.expr "." SUPER * * "#" is not an operator of regular Java. It separates * a class name and a member name in an expression for static member @@ -1058,9 +1059,10 @@ public final class Parser implements TokenId { case '.' : lex.get(); t = lex.get(); - if (t == CLASS) { + if (t == CLASS) expr = parseDotClass(expr, 0); - } + else if (t == SUPER) + expr = Expr.make('.', new Symbol(toClassName(expr)), new Keyword(t)); else if (t == Identifier) { str = lex.getString(); expr = Expr.make('.', expr, new Member(str)); diff --git a/src/main/javassist/compiler/TypeChecker.java b/src/main/javassist/compiler/TypeChecker.java index 35a8e378..d2814626 100644 --- a/src/main/javassist/compiler/TypeChecker.java +++ b/src/main/javassist/compiler/TypeChecker.java @@ -656,28 +656,34 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { false); else if (op == '.') { ASTree target = e.oprand1(); - try { - target.accept(this); - } - catch (NoFieldException nfe) { - if (nfe.getExpr() != target) - throw nfe; - - // it should be a static method. - exprType = CLASS; - arrayDim = 0; - className = nfe.getField(); // JVM-internal - e.setOperator(MEMBER); - e.setOprand1(new Symbol(MemberResolver.jvmToJavaName( - className))); + String classFollowedByDotSuper = isDotSuper(target); + if (classFollowedByDotSuper != null) + targetClass = MemberResolver.getSuperInterface(thisClass, + classFollowedByDotSuper); + else { + try { + target.accept(this); + } + catch (NoFieldException nfe) { + if (nfe.getExpr() != target) + throw nfe; + + // it should be a static method. + exprType = CLASS; + arrayDim = 0; + className = nfe.getField(); // JVM-internal + e.setOperator(MEMBER); + e.setOprand1(new Symbol(MemberResolver.jvmToJavaName( + className))); + } + + if (arrayDim > 0) + targetClass = resolver.lookupClass(javaLangObject, true); + else if (exprType == CLASS /* && arrayDim == 0 */) + targetClass = resolver.lookupClassByJvmName(className); + else + badMethod(); } - - if (arrayDim > 0) - targetClass = resolver.lookupClass(javaLangObject, true); - else if (exprType == CLASS /* && arrayDim == 0 */) - targetClass = resolver.lookupClassByJvmName(className); - else - badMethod(); } else badMethod(); @@ -695,6 +701,26 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { } /** + * Returns non-null if target is something like Foo.super + * for accessing the default method in an interface. + * Otherwise, null. + * + * @return the class name followed by {@code .super} or null. + */ + static String isDotSuper(ASTree target) { + if (target instanceof Expr) { + Expr e = (Expr)target; + if (e.getOperator() == '.') { + ASTree right = e.oprand2(); + if (right instanceof Keyword && ((Keyword)right).get() == SUPER) + return ((Symbol)e.oprand1()).get(); + } + } + + return null; + } + + /** * @return a pair of the class declaring the invoked method * and the MethodInfo of that method. Never null. */ |