Browse Source

fiexed JASSIST-238

tags/rel_3_19_0_ga
chibash 9 years ago
parent
commit
f2093c28be

+ 2
- 1
Readme.html View File

@@ -283,7 +283,8 @@ see javassist.Dump.

<p>-version 3.19
<ul>
<li>JIRA JASSIST-158, 205, 206, 207, 208, 209, 211, 212, 216, 220, 223, 224, 227, 230, 234, 235, 236.
<li>JIRA JASSIST-158, 205, 206, 207, 208, 209, 211, 212, 216, 220, 223, 224,
227, 230, 234, 235, 236, 237.
</ul>
</p>


BIN
javassist.jar View File


+ 32
- 5
src/main/javassist/bytecode/Bytecode.java View File

@@ -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);
}


+ 36
- 22
src/main/javassist/compiler/MemberCodeGen.java View File

@@ -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();

+ 14
- 0
src/main/javassist/compiler/MemberResolver.java View File

@@ -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('.', '/');
}

+ 4
- 2
src/main/javassist/compiler/Parser.java View File

@@ -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));

+ 47
- 21
src/main/javassist/compiler/TypeChecker.java View File

@@ -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();
@@ -694,6 +700,26 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
throw new CompileError("bad method");
}

/**
* 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.

+ 4
- 21
src/test/Test.java View File

@@ -2,27 +2,10 @@ import javassist.*;

public class Test {
public static void main(String[] args) throws Exception {
if (args.length > 1) {
new Test().bar(3);
return;
}

ClassPool cp = ClassPool.getDefault();
CtClass inner3 = cp.get("test2.Anon$Anon2.1");
CtBehavior ct = inner3.getEnclosingBehavior();
/* CtClass str = cp.get("java.lang.String");
CtClass cc = cp.get("Test");
cc.getClassFile().setMajorVersion(javassist.bytecode.ClassFile.JAVA_4);
CtMethod m = cc.getDeclaredMethod("bar");
m.addLocalVariable("aVar", str);
m.insertAfter(" dismiss( aVar );" , true);
cc.getClassFile().setMajorVersion(javassist.bytecode.ClassFile.JAVA_7);
m.insertBefore("aVar = initVar();");
cc.writeFile();*/
CtClass cc = cp.get("test5.DefaultMethod");
CtMethod m = CtNewMethod.make("public int run(){ return test5.DefaultMethodIntf.super.foo(); }", cc);
cc.addMethod(m);
cc.writeFile();
}

public void bar(int i) { foo(i); }
public void foo(int i) { System.out.println(i); }
public String initVar() { return "init"; }
public void dismiss(String s) { System.out.println(s); }
}

+ 1
- 0
src/test/javassist/JvstTest.java View File

@@ -1108,6 +1108,7 @@ public class JvstTest extends JvstTestRoot {
suite.addTestSuite(JvstTest2.class);
suite.addTestSuite(JvstTest3.class);
suite.addTestSuite(JvstTest4.class);
suite.addTestSuite(JvstTest5.class);
suite.addTestSuite(LoaderTestByRandall.class);
suite.addTestSuite(javassist.bytecode.BytecodeTest.class);
suite.addTestSuite(javassist.bytecode.StackMapTest.class);

+ 3
- 3
src/test/javassist/JvstTest4.java View File

@@ -5,7 +5,6 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashSet;
import java.util.List;

import javassist.bytecode.*;
import javassist.bytecode.annotation.Annotation;
@@ -662,8 +661,9 @@ public class JvstTest4 extends JvstTestRoot {
long t2 = endTime2 - endTime;
long t3 = endTime3 - endTime2;
System.out.println("JIRA150: " + t1 + ", " + t2 + ", " + t3);
assertTrue(t2 < t1 * 5);
assertTrue(t3 < t1 * 3);
assertTrue("performance test (the next try may succeed): " + t1 + "/ 5 < " + t2,
t2 < t1 * 5);
assertTrue("", t3 < t1 * 3);
}

public void testJIRA150b() throws Exception {

+ 34
- 0
src/test/javassist/JvstTest5.java View File

@@ -0,0 +1,34 @@
package javassist;

public class JvstTest5 extends JvstTestRoot {
public JvstTest5(String name) {
super(name);
}

public void testDollarClassInStaticMethod() throws Exception {
CtClass cc = sloader.makeClass("test5.DollarClass");
CtMethod m = CtNewMethod.make("public static int run(){ return $class.getName().length(); }", cc);
cc.addMethod(m);
m = CtNewMethod.make("public int run2(){ return $class.getName().length(); }", cc);
cc.addMethod(m);
cc.writeFile();
Object obj = make(cc.getName());
assertEquals(cc.getName().length(), invoke(obj, "run"));
assertEquals(cc.getName().length(), invoke(obj, "run2"));
}

public void testSuperDefaultMethodCall() throws Exception {
CtClass cc = sloader.get("test5.DefaultMethod");
CtMethod m = CtNewMethod.make("public int run(){ return test5.DefaultMethodIntf.super.foo(); }", cc);
cc.addMethod(m);
m = CtNewMethod.make("public int run2(){ return test5.DefaultMethodIntf.baz(); }", cc);
cc.addMethod(m);
m = CtNewMethod.make("public int run3(){ return test5.DefaultMethodIntf.super.baz(); }", cc);
cc.addMethod(m);
cc.writeFile();
Object obj = make(cc.getName());
assertEquals(1, invoke(obj, "run"));
assertEquals(10, invoke(obj, "run2"));
assertEquals(10, invoke(obj, "run3"));
}
}

+ 19
- 0
src/test/test5/DefaultMethod.java View File

@@ -0,0 +1,19 @@
package test5;

interface DefaultMethodSupIntf {
default int foo() { return 0; }
}

interface DefaultMethodIntf extends DefaultMethodSupIntf {
default int foo() { return 1; }
static int baz() { return 10; }
}

public class DefaultMethod implements DefaultMethodIntf {
public int bar() { return DefaultMethodIntf.super.foo(); }

public static void main(String[] args) {
int i = new DefaultMethod().bar() + new DefaultMethod().foo() + DefaultMethodIntf.baz();
System.out.println(i);
}
}

Loading…
Cancel
Save