Browse Source

Merge pull request #3 from jboss-javassist/master

Sync with base/master.
tags/rel_3_25_0_ga
Ning Zhang 5 years ago
parent
commit
6e6eb15d09
No account linked to committer's email address

+ 12
- 1
Readme.html View File



<h2>Changes</h2> <h2>Changes</h2>


<p>-version 3.25
<ul>
<li>GitHub Issue #72 (PR #231), #241, #242 (PR #243), PR #244.
</ul>

<p>-version 3.24.1 on December 9, 2018
<ul>
<li>GitHub Issue #228, #229</li>
<ul>
</p>

<p>-version 3.24 on November 1, 2018 <p>-version 3.24 on November 1, 2018
<ul> <ul>
<li>Java 11 supports.</li>
<li>Java 11 supports.</li>
<li>JIRA JASSIST-267.</li> <li>JIRA JASSIST-267.</li>
<li>Github PR #218.</li> <li>Github PR #218.</li>
</ul> </ul>

+ 1
- 1
build.xml View File



<project name="javassist" default="jar" basedir="."> <project name="javassist" default="jar" basedir=".">


<property name="dist-version" value="javassist-3.24-GA"/>
<property name="dist-version" value="javassist-3.24.1-GA"/>


<property environment="env"/> <property environment="env"/>
<property name="target.jar" value="javassist.jar"/> <property name="target.jar" value="javassist.jar"/>

BIN
javassist.jar View File


+ 2
- 1
pom.xml View File

Javassist (JAVA programming ASSISTant) makes Java bytecode manipulation Javassist (JAVA programming ASSISTant) makes Java bytecode manipulation
simple. It is a class library for editing bytecodes in Java. simple. It is a class library for editing bytecodes in Java.
</description> </description>
<version>3.24.0-GA</version>
<version>3.24.1-GA</version>
<name>Javassist</name> <name>Javassist</name>
<url>http://www.javassist.org/</url> <url>http://www.javassist.org/</url>


Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.</i>]]></bottom> Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
<show>public</show> <show>public</show>
<nohelp>true</nohelp> <nohelp>true</nohelp>
<doclint>none</doclint>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>

+ 1
- 1
src/main/META-INF/MANIFEST.MF View File

Specification-Title: Javassist Specification-Title: Javassist
Specification-Vendor: Shigeru Chiba, www.javassist.org Specification-Vendor: Shigeru Chiba, www.javassist.org
Specification-Version: 3.24.0-GA
Specification-Version: 3.24.1-GA
Main-Class: javassist.CtClass Main-Class: javassist.CtClass
Automatic-Module-Name: org.javassist Automatic-Module-Name: org.javassist

+ 37
- 0
src/main/javassist/CodeConverter.java View File

import javassist.convert.TransformAfter; import javassist.convert.TransformAfter;
import javassist.convert.TransformBefore; import javassist.convert.TransformBefore;
import javassist.convert.TransformCall; import javassist.convert.TransformCall;
import javassist.convert.TransformCallToStatic;
import javassist.convert.TransformFieldAccess; import javassist.convert.TransformFieldAccess;
import javassist.convert.TransformNew; import javassist.convert.TransformNew;
import javassist.convert.TransformNewClass; import javassist.convert.TransformNewClass;
= new TransformCall(transformers, oldMethodName, newMethod); = new TransformCall(transformers, oldMethodName, newMethod);
} }


/**
* Redirect non-static method invocations in a method body to a static
* method. The return type must be same with the originally invoked method.
* As parameters, the static method receives
* the target object and all the parameters to the originally invoked
* method. For example, if the originally invoked method is
* <code>move()</code>:
*
* <pre>class Point {
* Point move(int x, int y) { ... }
* }</pre>
*
* <p>Then the static method must be something like this:
*
* <pre>class Verbose {
* static Point print(Point target, int x, int y) { ... }
* }</pre>
*
* <p>The <code>CodeConverter</code> would translate bytecode
* equivalent to:
*
* <pre>Point p2 = p.move(x + y, 0);</pre>
*
* <p>into the bytecode equivalent to:
*
* <pre>Point p2 = Verbose.print(p, x + y, 0);</pre>
*
* @param origMethod original method
* @param staticMethod static method
*/
public void redirectMethodCallToStatic(CtMethod origMethod,
CtMethod staticMethod) {
transformers = new TransformCallToStatic(transformers, origMethod,
staticMethod);
}

/** /**
* Insert a call to another method before an existing method call. * Insert a call to another method before an existing method call.
* That "before" method must be static. The return type must be * That "before" method must be static. The return type must be

+ 1
- 1
src/main/javassist/CtBehavior.java View File

Modifier.isStatic(getModifiers())); Modifier.isStatic(getModifiers()));
jv.recordParamNames(ca, nvars); jv.recordParamNames(ca, nvars);
jv.recordLocalVariables(ca, 0); jv.recordLocalVariables(ca, 0);
jv.recordType(getReturnType0());
jv.recordReturnType(getReturnType0(), false);
jv.compileStmnt(src); jv.compileStmnt(src);
Bytecode b = jv.getBytecode(); Bytecode b = jv.getBytecode();
int stack = b.getMaxStack(); int stack = b.getMaxStack();

+ 1
- 1
src/main/javassist/CtClass.java View File

/** /**
* The version number of this release. * The version number of this release.
*/ */
public static final String version = "3.24.0-GA";
public static final String version = "3.24.1-GA";


/** /**
* Prints the version number and the copyright notice. * Prints the version number and the copyright notice.

+ 50
- 2
src/main/javassist/compiler/CodeGen.java View File

} }


private void atSwitchStmnt(Stmnt st) throws CompileError { private void atSwitchStmnt(Stmnt st) throws CompileError {
boolean isString = false;
if (typeChecker != null) {
doTypeCheck(st.head());
isString = typeChecker.exprType == TypeChecker.CLASS
&& typeChecker.arrayDim == 0
&& TypeChecker.jvmJavaLangString.equals(typeChecker.className);
}

compileExpr(st.head()); compileExpr(st.head());
int tmpVar = -1;
if (isString) {
tmpVar = getMaxLocals();
incMaxLocals(1);
bytecode.addAstore(tmpVar);
bytecode.addAload(tmpVar);
bytecode.addInvokevirtual(TypeChecker.jvmJavaLangString, "hashCode", "()I");
}


List<Integer> prevBreakList = breakList; List<Integer> prevBreakList = breakList;
breakList = new ArrayList<Integer>(); breakList = new ArrayList<Integer>();
bytecode.addGap(npairs * 8); bytecode.addGap(npairs * 8);


long[] pairs = new long[npairs]; long[] pairs = new long[npairs];
ArrayList<Integer> gotoDefaults = new ArrayList<Integer>();
int ipairs = 0; int ipairs = 0;
int defaultPc = -1; int defaultPc = -1;
for (ASTList list = body; list != null; list = list.tail()) { for (ASTList list = body; list != null; list = list.tail()) {
else if (op != CASE) else if (op != CASE)
fatal(); fatal();
else { else {
int curPos = bytecode.currentPc();
long caseLabel;
if (isString) {
// computeStringLabel() also adds bytecode as its side-effects.
caseLabel = (long)computeStringLabel(label.head(), tmpVar, gotoDefaults);
}
else
caseLabel = (long)computeLabel(label.head());

pairs[ipairs++] pairs[ipairs++]
= ((long)computeLabel(label.head()) << 32) +
((long)(bytecode.currentPc() - opcodePc) & 0xffffffff);
= (caseLabel << 32) +
((long)(curPos - opcodePc) & 0xffffffff);
} }


hasReturned = false; hasReturned = false;
defaultPc = endPc; defaultPc = endPc;


bytecode.write32bit(opcodePc2, defaultPc - opcodePc); bytecode.write32bit(opcodePc2, defaultPc - opcodePc);
for (int addr: gotoDefaults)
bytecode.write16bit(addr, defaultPc - addr + 1);


patchGoto(breakList, endPc); patchGoto(breakList, endPc);
breakList = prevBreakList; breakList = prevBreakList;
throw new CompileError("bad case label"); throw new CompileError("bad case label");
} }


private int computeStringLabel(ASTree expr, int tmpVar, List<Integer> gotoDefaults)
throws CompileError
{
doTypeCheck(expr);
expr = TypeChecker.stripPlusExpr(expr);
if (expr instanceof StringL) {
String label = ((StringL)expr).get();
bytecode.addAload(tmpVar);
bytecode.addLdc(label);
bytecode.addInvokevirtual(TypeChecker.jvmJavaLangString, "equals",
"(Ljava/lang/Object;)Z");
bytecode.addOpcode(IFEQ);
Integer pc = Integer.valueOf(bytecode.currentPc());
bytecode.addIndex(0);
gotoDefaults.add(pc);
return (int)label.hashCode();
}
throw new CompileError("bad case label");
}

private void atBreakStmnt(Stmnt st, boolean notCont) private void atBreakStmnt(Stmnt st, boolean notCont)
throws CompileError throws CompileError
{ {

+ 29
- 0
src/main/javassist/convert/TransformCallToStatic.java View File

package javassist.convert;

import javassist.CtMethod;
import javassist.bytecode.BadBytecode;
import javassist.bytecode.CodeIterator;
import javassist.bytecode.ConstPool;
import javassist.bytecode.Descriptor;
import javassist.bytecode.Opcode;

public class TransformCallToStatic extends TransformCall {
public TransformCallToStatic(Transformer next, CtMethod origMethod, CtMethod substMethod) {
super(next, origMethod, substMethod);
methodDescriptor = origMethod.getMethodInfo2().getDescriptor();
}

@Override
protected int match(int c, int pos, CodeIterator iterator, int typedesc, ConstPool cp) {
if (newIndex == 0) {
String desc = Descriptor.insertParameter(classname, methodDescriptor);
int nt = cp.addNameAndTypeInfo(newMethodname, desc);
int ci = cp.addClassInfo(newClassname);
newIndex = cp.addMethodrefInfo(ci, nt);
constPool = cp;
}
iterator.writeByte(Opcode.INVOKESTATIC, pos);
iterator.write16bit(newIndex, pos + 1);
return pos;
}
}

+ 0
- 3
src/main/javassist/util/proxy/DefineClassHelper.java View File

if (e instanceof RuntimeException) throw (RuntimeException) e; if (e instanceof RuntimeException) throw (RuntimeException) e;
throw new CannotCompileException(e); throw new CannotCompileException(e);
} }
finally {
SecurityActions.setAccessible(defineClass, false);
}
} }
} }



+ 0
- 3
src/main/javassist/util/proxy/DefinePackageHelper.java View File

} }
if (e instanceof RuntimeException) throw (RuntimeException) e; if (e instanceof RuntimeException) throw (RuntimeException) e;
} }
finally {
definePackage.setAccessible(false);
}
return null; return null;
} }
}; };

+ 13
- 3
src/main/javassist/util/proxy/ProxyFactory.java View File



/** /**
* Generates a proxy class using the current filter. * Generates a proxy class using the current filter.
* It loads a class file by the given
* {@code java.lang.invoke.MethodHandles.Lookup} object,
* which can be obtained by {@code MethodHandles.lookup()} called from
* somewhere in the package that the loaded class belongs to.
* *
* @param lookup used for loading the proxy class. * @param lookup used for loading the proxy class.
* It needs an appropriate right to invoke {@code defineClass} * It needs an appropriate right to invoke {@code defineClass}
* It needs an appropriate right to invoke {@code defineClass} * It needs an appropriate right to invoke {@code defineClass}
* for the proxy class. * for the proxy class.
* @param filter the filter. * @param filter the filter.
* @see #createClass(Lookup)
* @since 3.24 * @since 3.24
*/ */
public Class<?> createClass(Lookup lookup, MethodFilter filter) { public Class<?> createClass(Lookup lookup, MethodFilter filter) {
* {@code java.lang.invoke.MethodHandles.Lookup}. * {@code java.lang.invoke.MethodHandles.Lookup}.
*/ */
private Class<?> getClassInTheSamePackage() { private Class<?> getClassInTheSamePackage() {
if (basename.startsWith("javassist.util.proxy.")) // maybe the super class is java.*
if (basename.startsWith(packageForJavaBase)) // maybe the super class is java.*
return this.getClass(); return this.getClass();
else if (superClass != null && superClass != OBJECT_TYPE) else if (superClass != null && superClass != OBJECT_TYPE)
return superClass; return superClass;
if (Modifier.isFinal(superClass.getModifiers())) if (Modifier.isFinal(superClass.getModifiers()))
throw new RuntimeException(superName + " is final"); throw new RuntimeException(superName + " is final");


if (basename.startsWith("java.") || onlyPublicMethods)
basename = "javassist.util.proxy." + basename.replace('.', '_');
// Since java.base module is not opened, its proxy class should be
// in a different (open) module. Otherwise, it could not be created
// by reflection.
if (basename.startsWith("java.") || basename.startsWith("jdk.") || onlyPublicMethods)
basename = packageForJavaBase + basename.replace('.', '_');
} }


private static final String packageForJavaBase = "javassist.util.proxy.";

private void allocateClassName() { private void allocateClassName() {
classname = makeProxyName(basename); classname = makeProxyName(basename);
} }

+ 75
- 0
src/test/javassist/ConcurrentClassDefinitionTest.java View File

package javassist;

import javassist.bytecode.ClassFile;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

@RunWith(Parameterized.class)
public class ConcurrentClassDefinitionTest {

@Parameterized.Parameter
public int N;

@Parameterized.Parameters
public static Object[] data() {
return new Object[] {
1, // single threaded - should pass
Runtime.getRuntime().availableProcessors() * 2
};
}

@Test
public void showDefineClassRaceCondition() throws Exception{
Worker[] workers = new Worker[N];
for (int i = 0; i < N; i++) {
workers[i] = new Worker(N + "_ " + i, 100);
workers[i].start();
}
for (Worker w : workers) {
w.join();
}
for (Worker w : workers) {
if (w.e != null) {
throw w.e;
}
}
}

private static class Worker extends Thread {
String id;
int count;
Exception e;

Worker(String id, int count) {
this.id = id;
this.count = count;
}

@Override
public void run() {
try {
for (int i = 0; i < count; i++) {
Class c = makeClass(id + "_" + i);
assert c != null;
}
} catch (Exception e) {
this.e = e;
}
}

@Override
public void interrupt() {
super.interrupt();
}
}

private static Class makeClass(String id) throws Exception {
ClassFile cf = new ClassFile(
false, "com.example.JavassistGeneratedClass_" + id, null);
ClassPool classPool = ClassPool.getDefault();
return classPool.makeClass(cf).toClass();
}


}

+ 14
- 0
src/test/javassist/JvstTest3.java View File

assertEquals(524, invoke(obj, "test")); assertEquals(524, invoke(obj, "test"));
} }


public void testMethodRedirectToStatic() throws Exception {
CtClass targetClass = sloader.get("test3.MethodRedirectToStatic");
CtClass staticClass = sloader.get("test3.MethodRedirectToStatic2");
CtMethod targetMethod = targetClass.getDeclaredMethod("add");
CtMethod staticMethod = staticClass.getDeclaredMethod("add2");
CodeConverter conv = new CodeConverter();

conv.redirectMethodCallToStatic(targetMethod, staticMethod);
targetClass.instrument(conv);
targetClass.writeFile();
Object obj = make(targetClass.getName());
assertEquals(30, invoke(obj, "test"));
}

public void testClassMap() throws Exception { public void testClassMap() throws Exception {
ClassMap map = new ClassMap(); ClassMap map = new ClassMap();
map.put("aa", "AA"); map.put("aa", "AA");

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

cc.getClassFile().compact(); cc.getClassFile().compact();
cc.toClass(test5.DefineClassCapability.class); cc.toClass(test5.DefineClassCapability.class);
} }

public void testSwitchCaseWithStringConstant() throws Exception {
CtClass cc = sloader.get("test5.SwitchCase");
cc.addMethod(CtNewMethod.make(
"public int run() {" +
" String s = \"foobar\";\n" +
" switch (s) {\n" +
" case STR1: return 1;\n" +
" case \"foobar\": return 2;\n" +
" default: return 3; }\n" +
"}\n", cc));
cc.writeFile();
Object obj = make(cc.getName());
assertEquals(2, invoke(obj, "run"));
}

public void testSwitchCaseWithStringConstant2() throws Exception {
CtClass cc = sloader.makeClass("test5.SwitchCase2");
cc.addMethod(CtNewMethod.make(
"public int run() {" +
" String s = \"foo\";\n" +
" switch (s) {\n" +
" case test5.SwitchCase.STR1: return 1;\n" +
" case \"foobar\": return 2;\n" +
" }\n" +
" return 3;\n" +
"}\n", cc));
cc.writeFile();
Object obj = make(cc.getName());
assertEquals(1, invoke(obj, "run"));
}

// Issue #241
public void testInsertBeforeAndDollarR() throws Exception {
CtClass cc = sloader.get(test5.InsertBeforeDollarR.class.getName());
CtMethod m = cc.getDeclaredMethod("foo");
m.insertBefore("{ if ($1 == 1) return ($r)$2; }");
try {
m.insertBefore("{ $_ = \"bar\"; }");
assertTrue(false);
} catch (CannotCompileException e) {}
cc.writeFile();
Object obj = make(cc.getName());
assertEquals(1, invoke(obj, "run"));
}
} }

+ 12
- 0
src/test/javassist/proxyfactory/ProxyFactoryTest.java View File

} }
}); });
} }

public void testJava11jdk() throws Exception {
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(jdk.javadoc.doclet.StandardDoclet.class);
jdk.javadoc.doclet.StandardDoclet e = (jdk.javadoc.doclet.StandardDoclet)factory.create(null, null, new MethodHandler() {
@Override
public Object invoke(Object self, Method thisMethod,
Method proceed, Object[] args) throws Throwable {
return proceed.invoke(self, args);
}
});
}
} }

+ 22
- 0
src/test/test3/MethodRedirectToStatic.java View File

package test3;

public class MethodRedirectToStatic {

public static void main(String[] args) {
System.out.println(new MethodRedirectToStatic().test());
}

int add(int a, int b) {
return a + b;
}

public int test() {
return add(1, 2);
}
}

class MethodRedirectToStatic2 {
public static int add2(MethodRedirectToStatic target, int a, int b) {
return target.add(a * 10, b * 10);
}
}

+ 14
- 0
src/test/test5/InsertBeforeDollarR.java View File

package test5;

public class InsertBeforeDollarR {
public int run() {
if (foo(1, "baz").equals("baz"))
return 1;
else
return 0;
}

public String foo(int i, Object obj) {
return String.valueOf(i);
}
}

+ 5
- 0
src/test/test5/SwitchCase.java View File

package test5;

public class SwitchCase {
public static final String STR1 = "foo";
}

Loading…
Cancel
Save