Ver código fonte

made automatic pruning off by default because I found that pruning does not really save memory (only 20%). I changed Javassist to compress a class file on memory after toBytecode().


git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@383 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
tags/rel_3_17_1_ga
chiba 17 anos atrás
pai
commit
73969fa11a

+ 8
- 1
Readme.html Ver arquivo

<p>-version 3.6 <p>-version 3.6


<ul> <ul>
<li>The stack map table introduced since Java 6 has been supported.
<li>The stack map table introduced since Java 6 has been supported.
<li>CtClass#getDeclaredBehaviors() now returns a class initializer
as well as methods and constructors.
<li>The default status of automatic pruning was made off.
Instead of pruning, this version of Javassist compresses
the data structure of a class file after toBytecode() is called.
The compressed class file is automatically decompressed when needed.
This saves memory space better than pruning.
<li><a href="http://jira.jboss.com/jira/browse/JASSIST-33">JIRA JASSIST-33</a> has been fixed. <li><a href="http://jira.jboss.com/jira/browse/JASSIST-33">JIRA JASSIST-33</a> has been fixed.
</ul> </ul>



+ 3
- 2
src/main/javassist/ClassPool.java Ver arquivo

* are called. The automatic pruning can be turned on/off individually * are called. The automatic pruning can be turned on/off individually
* for each <code>CtClass</code> object. * for each <code>CtClass</code> object.
* *
* <p>The initial value is true.
* <p>The initial value is false.
* *
* @see CtClass#prune() * @see CtClass#prune()
* @see CtClass#stopPruning(boolean) * @see CtClass#stopPruning(boolean)
* @see CtClass#detach()
*/ */
public static boolean doPruning = true;
public static boolean doPruning = false;


/* releaseUnmodifiedClassFile was introduced for avoiding a bug /* releaseUnmodifiedClassFile was introduced for avoiding a bug
of JBoss AOP. So the value should be true except for JBoss AOP. of JBoss AOP. So the value should be true except for JBoss AOP.

+ 13
- 5
src/main/javassist/CtClass.java Ver arquivo

/** /**
* The version number of this release. * The version number of this release.
*/ */
public static final String version = "3.6.0BETA";
public static final String version = "3.6.0beta2";


/** /**
* Prints the version number and the copyright notice. * Prints the version number and the copyright notice.
* save memory consumption. * save memory consumption.
* *
* <p>If <code>ClassPool.doPruning</code> is true, the automatic pruning * <p>If <code>ClassPool.doPruning</code> is true, the automatic pruning
* is on by default. Otherwise, it is off.
* is on by default. Otherwise, it is off. The default value of
* <code>ClassPool.doPruning</code> is false.
* *
* @param stop disallow pruning if true. Otherwise, allow. * @param stop disallow pruning if true. Otherwise, allow.
* @return the previous status of pruning. true if pruning is already stopped. * @return the previous status of pruning. true if pruning is already stopped.
* are still accessible. * are still accessible.
* *
* <p><code>toBytecode()</code>, <code>writeFile()</code>, and * <p><code>toBytecode()</code>, <code>writeFile()</code>, and
* <code>toClass()</code> internally call this method.
* <code>toClass()</code> internally call this method if
* automatic pruning is on.
*
* <p>According to some experiments, pruning does not really reduce
* memory consumption. Only about 20%. Since pruning takes time,
* it might not pay off. So the automatic pruning is off by default.
*
* @see #stopPruning(boolean)
* @see #detach()
* @see ClassPool#doPruning
* *
* @see #toBytecode() * @see #toBytecode()
* @see #toClass() * @see #toClass()
* @see #writeFile() * @see #writeFile()
* @see #instrument(CodeConverter) * @see #instrument(CodeConverter)
* @see #instrument(ExprEditor) * @see #instrument(ExprEditor)
*
* @see #stopPruning(boolean)
*/ */
public void prune() {} public void prune() {}



+ 293
- 210
src/main/javassist/CtClassType.java Ver arquivo



package javassist; package javassist;


import java.lang.ref.WeakReference;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
boolean wasPruned; boolean wasPruned;
boolean memberRemoved; boolean memberRemoved;
ClassFile classfile; ClassFile classfile;
byte[] rawClassfile; // backup storage


private CtMember fieldsCache;
private CtMember methodsCache;
private CtMember constructorsCache;
private CtConstructor classInitializerCache;

private WeakReference memberCache;
private AccessorMaker accessors; private AccessorMaker accessors;


private FieldInitLink fieldInitializers; private FieldInitLink fieldInitializers;
int getCounter; int getCounter;
private static int readCounter = 0; private static int readCounter = 0;
private static final int READ_THRESHOLD = 100; // see getClassFile2() private static final int READ_THRESHOLD = 100; // see getClassFile2()
private static final int GET_THRESHOLD = 2; // see releaseClassFiles()


CtClassType(String name, ClassPool cp) { CtClassType(String name, ClassPool cp) {
super(name); super(name);
classPool = cp; classPool = cp;
wasChanged = wasFrozen = wasPruned = memberRemoved = false; wasChanged = wasFrozen = wasPruned = memberRemoved = false;
classfile = null; classfile = null;
rawClassfile = null;
memberCache = null;
accessors = null; accessors = null;
fieldInitializers = null; fieldInitializers = null;
hiddenMethods = null; hiddenMethods = null;
uniqueNumberSeed = 0; uniqueNumberSeed = 0;
eraseCache();
getCounter = 0; getCounter = 0;
} }


buffer.append(" extends ??"); buffer.append(" extends ??");
} }


CtMember field = getFieldsCache();
buffer.append(" fields=");
while (field != null) {
buffer.append(field);
buffer.append(", ");
field = field.next;
}

CtMember c = getConstructorsCache();
buffer.append(" constructors=");
while (c != null) {
buffer.append(c);
buffer.append(", ");
c = c.next;
}
CtMember.Cache memCache = getMembers();
exToString(buffer, " fields=",
memCache.fieldHead(), memCache.lastField());
exToString(buffer, " constructors=",
memCache.consHead(), memCache.lastCons());
exToString(buffer, " methods=",
memCache.methodHead(), memCache.lastMethod());
}


CtMember m = getMethodsCache();
buffer.append(" methods=");
while (m != null) {
buffer.append(m);
private void exToString(StringBuffer buffer, String msg,
CtMember head, CtMember tail) {
buffer.append(msg);
while (head != tail) {
head = head.next();
buffer.append(head);
buffer.append(", "); buffer.append(", ");
m = m.next;
} }
} }


protected void eraseCache() {
fieldsCache = null;
constructorsCache = null;
classInitializerCache = null;
methodsCache = null;
}

public AccessorMaker getAccessorMaker() { public AccessorMaker getAccessorMaker() {
if (accessors == null) if (accessors == null)
accessors = new AccessorMaker(this); accessors = new AccessorMaker(this);
} }


public ClassFile getClassFile2() { public ClassFile getClassFile2() {
if (classfile != null)
return classfile;
ClassFile cfile = classfile;
if (cfile != null)
return cfile;


if (readCounter++ > READ_THRESHOLD
&& ClassPool.releaseUnmodifiedClassFile) {
if (readCounter++ > READ_THRESHOLD) {
getCounter += 2;
releaseClassFiles(); releaseClassFiles();
readCounter = 0; readCounter = 0;
} }


if (rawClassfile != null) {
try {
classfile = new ClassFile(new DataInputStream(
new ByteArrayInputStream(rawClassfile)));
rawClassfile = null;
getCounter = GET_THRESHOLD;
return classfile;
}
catch (IOException e) {
throw new RuntimeException(e.toString(), e);
}
}

InputStream fin = null; InputStream fin = null;
try { try {
fin = classPool.openClassfile(getName()); fin = classPool.openClassfile(getName());
throw new NotFoundException(getName()); throw new NotFoundException(getName());


fin = new BufferedInputStream(fin); fin = new BufferedInputStream(fin);
classfile = new ClassFile(new DataInputStream(fin));
if (!classfile.getName().equals(qualifiedName))
ClassFile cf = new ClassFile(new DataInputStream(fin));
if (!cf.getName().equals(qualifiedName))
throw new RuntimeException("cannot find " + qualifiedName + ": " throw new RuntimeException("cannot find " + qualifiedName + ": "
+ classfile.getName() + " found in "
+ cf.getName() + " found in "
+ qualifiedName.replace('.', '/') + ".class"); + qualifiedName.replace('.', '/') + ".class");


return classfile;
classfile = cf;
return cf;
} }
catch (NotFoundException e) { catch (NotFoundException e) {
throw new RuntimeException(e.toString());
throw new RuntimeException(e.toString(), e);
} }
catch (IOException e) { catch (IOException e) {
throw new RuntimeException(e.toString());
throw new RuntimeException(e.toString(), e);
} }
finally { finally {
if (fin != null) if (fin != null)
} }
} }


/**
* Converts a ClassFile object into a byte array
* for saving memory space.
*/
public synchronized void saveClassFile() {
/* getMembers() and releaseClassFile() are also synchronized.
*/
if (classfile == null || hasMemberCache() != null)
return;

ByteArrayOutputStream barray = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(barray);
try {
classfile.write(out);
barray.close();
rawClassfile = barray.toByteArray();
classfile = null;
}
catch (IOException e) {}
}

public synchronized void releaseClassFile() {
if (!isModified())
classfile = null;
}

/* Inherited from CtClass. Called by get() in ClassPool. /* Inherited from CtClass. Called by get() in ClassPool.
* *
* @see javassist.CtClass#incGetCounter() * @see javassist.CtClass#incGetCounter()
* @see #toBytecode(DataOutputStream)
*/ */
void incGetCounter() { ++getCounter; } void incGetCounter() { ++getCounter; }


/** /**
* Releases the class files and cached CtBehaviors
* Releases the class files
* of the CtClasses that have not been recently used * of the CtClasses that have not been recently used
* if they are unmodified. * if they are unmodified.
*/ */
Object obj = e.nextElement(); Object obj = e.nextElement();
if (obj instanceof CtClassType) { if (obj instanceof CtClassType) {
CtClassType cct = (CtClassType)obj; CtClassType cct = (CtClassType)obj;
if (cct.getCounter < 2 && !cct.isModified()) {
cct.eraseCache();
cct.classfile = null;
}
if (cct.getCounter < GET_THRESHOLD)
if (!cct.isModified() && ClassPool.releaseUnmodifiedClassFile)
cct.releaseClassFile();
else if (cct.isFrozen() && !cct.wasPruned)
cct.saveClassFile();


cct.getCounter = 0; cct.getCounter = 0;
} }
ClassFile cf = getClassFile2(); ClassFile cf = getClassFile2();
super.setName(name); super.setName(name);
cf.setName(name); cf.setName(name);
eraseCache();
nameReplaced();
classPool.classNameChanged(oldname, this); classPool.classNameChanged(oldname, this);
} }


super.replaceClassName(classnames); super.replaceClassName(classnames);
ClassFile cf = getClassFile2(); ClassFile cf = getClassFile2();
cf.renameClass(classnames); cf.renameClass(classnames);
eraseCache();
nameReplaced();


if (newClassName != null) { if (newClassName != null) {
super.setName(newClassName); super.setName(newClassName);
else { else {
super.replaceClassName(oldname, newname); super.replaceClassName(oldname, newname);
getClassFile2().renameClass(oldname, newname); getClassFile2().renameClass(oldname, newname);
eraseCache();
nameReplaced();
} }
} }


return c; return c;
} }


/* flush cached names.
*/
private void nameReplaced() {
CtMember.Cache cache = hasMemberCache();
if (cache != null) {
CtMember mth = cache.methodHead();
CtMember tail = cache.lastMethod();
while (mth != tail) {
mth = mth.next();
mth.nameReplaced();
}
}
}

/**
* Returns null if members are not cached.
*/
protected CtMember.Cache hasMemberCache() {
if (memberCache != null)
return (CtMember.Cache)memberCache.get();
else
return null;
}

protected synchronized CtMember.Cache getMembers() {
CtMember.Cache cache = null;
if (memberCache == null
|| (cache = (CtMember.Cache)memberCache.get()) == null) {
cache = new CtMember.Cache(this);
makeFieldCache(cache);
makeBehaviorCache(cache);
memberCache = new WeakReference(cache);
}

return cache;
}

private void makeFieldCache(CtMember.Cache cache) {
List list = getClassFile2().getFields();
int n = list.size();
for (int i = 0; i < n; ++i) {
FieldInfo finfo = (FieldInfo)list.get(i);
CtField newField = new CtField(finfo, this);
cache.addField(newField);
}
}

private void makeBehaviorCache(CtMember.Cache cache) {
List list = getClassFile2().getMethods();
int n = list.size();
for (int i = 0; i < n; ++i) {
MethodInfo minfo = (MethodInfo)list.get(i);
if (minfo.isMethod()) {
CtMethod newMethod = new CtMethod(minfo, this);
cache.addMethod(newMethod);
}
else {
CtConstructor newCons = new CtConstructor(minfo, this);
cache.addConstructor(newCons);
}
}
}

public CtField[] getFields() { public CtField[] getFields() {
ArrayList alist = new ArrayList(); ArrayList alist = new ArrayList();
getFields(alist, this); getFields(alist, this);
} }
catch (NotFoundException e) {} catch (NotFoundException e) {}


CtMember cf = ((CtClassType)cc).getFieldsCache();
while (cf != null) {
if (!Modifier.isPrivate(cf.getModifiers()))
alist.add(cf);

cf = cf.next;
CtMember.Cache memCache = ((CtClassType)cc).getMembers();
CtMember field = memCache.fieldHead();
CtMember tail = memCache.lastField();
while (field != tail) {
field = field.next();
if (!Modifier.isPrivate(field.getModifiers()))
alist.add(field);
} }
} }


} }


public CtField[] getDeclaredFields() { public CtField[] getDeclaredFields() {
CtMember cf = getFieldsCache();
int num = CtField.count(cf);
CtMember.Cache memCache = getMembers();
CtMember field = memCache.fieldHead();
CtMember tail = memCache.lastField();
int num = CtMember.Cache.count(field, tail);
CtField[] cfs = new CtField[num]; CtField[] cfs = new CtField[num];
int i = 0; int i = 0;
while (cf != null) {
cfs[i++] = (CtField)cf;
cf = cf.next;
while (field != tail) {
field = field.next();
cfs[i++] = (CtField)field;
} }


return cfs; return cfs;
} }


protected CtMember getFieldsCache() {
if (fieldsCache == null) {
List list = getClassFile2().getFields();
int n = list.size();
CtMember allFields = null;
CtField tail = null;
for (int i = 0; i < n; ++i) {
FieldInfo finfo = (FieldInfo)list.get(i);
CtField newTail = new CtField(finfo, this);
allFields = CtMember.append(allFields, tail, newTail);
tail = newTail;
}

fieldsCache = allFields;
}

return fieldsCache;
}

public CtField getDeclaredField(String name) throws NotFoundException { public CtField getDeclaredField(String name) throws NotFoundException {
CtField f = getDeclaredField2(name); CtField f = getDeclaredField2(name);
if (f == null) if (f == null)
} }


private CtField getDeclaredField2(String name) { private CtField getDeclaredField2(String name) {
CtMember cf = getFieldsCache();
while (cf != null) {
if (cf.getName().equals(name))
return (CtField)cf;

cf = cf.next;
CtMember.Cache memCache = getMembers();
CtMember field = memCache.fieldHead();
CtMember tail = memCache.lastField();
while (field != tail) {
field = field.next();
if (field.getName().equals(name))
return (CtField)field;
} }


return null; return null;
} }


public CtBehavior[] getDeclaredBehaviors() { public CtBehavior[] getDeclaredBehaviors() {
CtMember cc = getConstructorsCache();
CtMember cm = getMethodsCache();
int num = CtMember.count(cm) + CtMember.count(cc);
CtBehavior[] cb = new CtBehavior[num];
CtMember.Cache memCache = getMembers();
CtMember cons = memCache.consHead();
CtMember consTail = memCache.lastCons();
int cnum = CtMember.Cache.count(cons, consTail);
CtMember mth = memCache.methodHead();
CtMember mthTail = memCache.lastMethod();
int mnum = CtMember.Cache.count(mth, mthTail);

CtBehavior[] cb = new CtBehavior[cnum + mnum];
int i = 0; int i = 0;
while (cc != null) {
cb[i++] = (CtBehavior)cc;
cc = cc.next;
while (cons != consTail) {
cons = cons.next();
cb[i++] = (CtBehavior)cons;
} }


while (cm != null) {
cb[i++] = (CtBehavior)cm;
cm = cm.next;
while (mth != mthTail) {
mth = mth.next();
cb[i++] = (CtBehavior)mth;
} }


return cb; return cb;
} }


public CtConstructor[] getConstructors() { public CtConstructor[] getConstructors() {
CtConstructor[] cons = getDeclaredConstructors();
if (cons.length == 0)
return cons;
CtMember.Cache memCache = getMembers();
CtMember cons = memCache.consHead();
CtMember consTail = memCache.lastCons();


int n = 0; int n = 0;
int i = cons.length;
while (--i >= 0)
if (!Modifier.isPrivate(cons[i].getModifiers()))
++n;
CtMember mem = cons;
while (mem != consTail) {
mem = mem.next();
if (isPubCons((CtConstructor)mem))
n++;
}


CtConstructor[] result = new CtConstructor[n]; CtConstructor[] result = new CtConstructor[n];
n = 0;
i = cons.length;
while (--i >= 0) {
CtConstructor c = cons[i];
if (!Modifier.isPrivate(c.getModifiers()))
result[n++] = c;
int i = 0;
mem = cons;
while (mem != consTail) {
mem = mem.next();
CtConstructor cc = (CtConstructor)mem;
if (isPubCons(cc))
result[i++] = cc;
} }


return result; return result;
} }


private static boolean isPubCons(CtConstructor cons) {
return !Modifier.isPrivate(cons.getModifiers())
&& cons.isConstructor();
}

public CtConstructor getConstructor(String desc) public CtConstructor getConstructor(String desc)
throws NotFoundException throws NotFoundException
{ {
CtConstructor cc = (CtConstructor)getConstructorsCache();
while (cc != null) {
if (cc.getMethodInfo2().getDescriptor().equals(desc))
CtMember.Cache memCache = getMembers();
CtMember cons = memCache.consHead();
CtMember consTail = memCache.lastCons();

while (cons != consTail) {
cons = cons.next();
CtConstructor cc = (CtConstructor)cons;
if (cc.getMethodInfo2().getDescriptor().equals(desc)
&& cc.isConstructor())
return cc; return cc;

cc = (CtConstructor)cc.next;
} }


return super.getConstructor(desc); return super.getConstructor(desc);
} }


public CtConstructor[] getDeclaredConstructors() { public CtConstructor[] getDeclaredConstructors() {
CtMember cc = getConstructorsCache();
int num = CtMember.count(cc);
CtConstructor[] ccs = new CtConstructor[num];
int i = 0;
while (cc != null) {
ccs[i++] = (CtConstructor)cc;
cc = cc.next;
}

return ccs;
}

protected CtMember getConstructorsCache() {
if (constructorsCache == null) {
List list = getClassFile2().getMethods();
int n = list.size();
CtMember allConstructors = null;
CtConstructor tail = null;
for (int i = 0; i < n; ++i) {
MethodInfo minfo = (MethodInfo)list.get(i);
if (minfo.isConstructor()) {
CtConstructor newTail = new CtConstructor(minfo, this);
allConstructors = CtMember.append(allConstructors, tail, newTail);
tail = newTail;
}
}
CtMember.Cache memCache = getMembers();
CtMember cons = memCache.consHead();
CtMember consTail = memCache.lastCons();


constructorsCache = allConstructors;
int n = 0;
CtMember mem = cons;
while (mem != consTail) {
mem = mem.next();
CtConstructor cc = (CtConstructor)mem;
if (cc.isConstructor())
n++;
} }


return constructorsCache;
CtConstructor[] result = new CtConstructor[n];
int i = 0;
mem = cons;
while (mem != consTail) {
mem = mem.next();
CtConstructor cc = (CtConstructor)mem;
if (cc.isConstructor())
result[i++] = cc;
}

return result;
} }


public CtConstructor getClassInitializer() { public CtConstructor getClassInitializer() {
if (classInitializerCache == null) {
MethodInfo minfo = getClassFile2().getStaticInitializer();
if (minfo != null)
classInitializerCache = new CtConstructor(minfo, this);
CtMember.Cache memCache = getMembers();
CtMember cons = memCache.consHead();
CtMember consTail = memCache.lastCons();

while (cons != consTail) {
cons = cons.next();
CtConstructor cc = (CtConstructor)cons;
if (cc.isClassInitializer())
return cc;
} }


return classInitializerCache;
return null;
} }


public CtMethod[] getMethods() { public CtMethod[] getMethods() {
catch (NotFoundException e) {} catch (NotFoundException e) {}


if (cc instanceof CtClassType) { if (cc instanceof CtClassType) {
CtMember cm = ((CtClassType)cc).getMethodsCache();
while (cm != null) {
if (!Modifier.isPrivate(cm.getModifiers()))
h.put(((CtMethod)cm).getStringRep(), cm);

cm = cm.next;
CtMember.Cache memCache = ((CtClassType)cc).getMembers();
CtMember mth = memCache.methodHead();
CtMember mthTail = memCache.lastMethod();

while (mth != mthTail) {
mth = mth.next();
if (!Modifier.isPrivate(mth.getModifiers()))
h.put(((CtMethod)mth).getStringRep(), mth);
} }
} }
} }
private static CtMethod getMethod0(CtClass cc, private static CtMethod getMethod0(CtClass cc,
String name, String desc) { String name, String desc) {
if (cc instanceof CtClassType) { if (cc instanceof CtClassType) {
CtMethod cm = (CtMethod)((CtClassType)cc).getMethodsCache();
while (cm != null) {
if (cm.getName().equals(name)
&& cm.getMethodInfo2().getDescriptor().equals(desc))
return cm;

cm = (CtMethod)cm.next;
CtMember.Cache memCache = ((CtClassType)cc).getMembers();
CtMember mth = memCache.methodHead();
CtMember mthTail = memCache.lastMethod();

while (mth != mthTail) {
mth = mth.next();
if (mth.getName().equals(name)
&& ((CtMethod)mth).getMethodInfo2().getDescriptor().equals(desc))
return (CtMethod)mth;
} }
} }


} }


public CtMethod[] getDeclaredMethods() { public CtMethod[] getDeclaredMethods() {
CtMember cm = getMethodsCache();
int num = CtMember.count(cm);
CtMember.Cache memCache = getMembers();
CtMember mth = memCache.methodHead();
CtMember mthTail = memCache.lastMethod();
int num = CtMember.Cache.count(mth, mthTail);
CtMethod[] cms = new CtMethod[num]; CtMethod[] cms = new CtMethod[num];
int i = 0; int i = 0;
while (cm != null) {
cms[i++] = (CtMethod)cm;
cm = cm.next;
while (mth != mthTail) {
mth = mth.next();
cms[i++] = (CtMethod)mth;
} }


return cms; return cms;
} }


public CtMethod getDeclaredMethod(String name) throws NotFoundException { public CtMethod getDeclaredMethod(String name) throws NotFoundException {
CtMember m = getMethodsCache();
while (m != null) {
if (m.getName().equals(name))
return (CtMethod)m;

m = m.next;
CtMember.Cache memCache = getMembers();
CtMember mth = memCache.methodHead();
CtMember mthTail = memCache.lastMethod();
while (mth != mthTail) {
mth = mth.next();
if (mth.getName().equals(name))
return (CtMethod)mth;
} }


throw new NotFoundException(name + "(..) is not found in " throw new NotFoundException(name + "(..) is not found in "
throws NotFoundException throws NotFoundException
{ {
String desc = Descriptor.ofParameters(params); String desc = Descriptor.ofParameters(params);
CtMethod m = (CtMethod)getMethodsCache();
while (m != null) {
if (m.getName().equals(name)
&& m.getMethodInfo2().getDescriptor().startsWith(desc))
return m;
CtMember.Cache memCache = getMembers();
CtMember mth = memCache.methodHead();
CtMember mthTail = memCache.lastMethod();


m = (CtMethod)m.next;
while (mth != mthTail) {
mth = mth.next();
if (mth.getName().equals(name)
&& ((CtMethod)mth).getMethodInfo2().getDescriptor().startsWith(desc))
return (CtMethod)mth;
} }


throw new NotFoundException(name + "(..) is not found in " throw new NotFoundException(name + "(..) is not found in "
+ getName()); + getName());
} }


protected CtMember getMethodsCache() {
if (methodsCache == null) {
List list = getClassFile2().getMethods();
int n = list.size();
CtMember allMethods = null;
CtMethod tail = null;
for (int i = 0; i < n; ++i) {
MethodInfo minfo = (MethodInfo)list.get(i);
if (minfo.isMethod()) {
CtMethod newTail = new CtMethod(minfo, this);
allMethods = CtMember.append(allMethods, tail, newTail);
tail = newTail;
}
}

methodsCache = allMethods;
}

return methodsCache;
}

public void addField(CtField f, String init) public void addField(CtField f, String init)
throws CannotCompileException throws CannotCompileException
{ {
catch (NotFoundException e) {} catch (NotFoundException e) {}
} }


getFieldsCache();
fieldsCache = CtField.append(fieldsCache, f);
getMembers().addField(f);
getClassFile2().addField(f.getFieldInfo2()); getClassFile2().addField(f.getFieldInfo2());


if (init != null) { if (init != null) {
FieldInfo fi = f.getFieldInfo2(); FieldInfo fi = f.getFieldInfo2();
ClassFile cf = getClassFile2(); ClassFile cf = getClassFile2();
if (cf.getFields().remove(fi)) { if (cf.getFields().remove(fi)) {
fieldsCache = CtMember.remove(fieldsCache, f);
getMembers().remove(f);
memberRemoved = true; memberRemoved = true;
} }
else else
if (c.getDeclaringClass() != this) if (c.getDeclaringClass() != this)
throw new CannotCompileException("cannot add"); throw new CannotCompileException("cannot add");


getConstructorsCache();
constructorsCache = (CtConstructor)CtMember.append(constructorsCache, c);
getMembers().addConstructor(c);
getClassFile2().addMethod(c.getMethodInfo2()); getClassFile2().addMethod(c.getMethodInfo2());
} }


MethodInfo mi = m.getMethodInfo2(); MethodInfo mi = m.getMethodInfo2();
ClassFile cf = getClassFile2(); ClassFile cf = getClassFile2();
if (cf.getMethods().remove(mi)) { if (cf.getMethods().remove(mi)) {
constructorsCache = CtMember.remove(constructorsCache, m);
getMembers().remove(m);
memberRemoved = true; memberRemoved = true;
} }
else else
if (m.getDeclaringClass() != this) if (m.getDeclaringClass() != this)
throw new CannotCompileException("cannot add"); throw new CannotCompileException("cannot add");


getMethodsCache();
methodsCache = CtMember.append(methodsCache, m);
getMembers().addMethod(m);
getClassFile2().addMethod(m.getMethodInfo2()); getClassFile2().addMethod(m.getMethodInfo2());
if ((m.getModifiers() & Modifier.ABSTRACT) != 0) if ((m.getModifiers() & Modifier.ABSTRACT) != 0)
setModifiers(getModifiers() | Modifier.ABSTRACT); setModifiers(getModifiers() | Modifier.ABSTRACT);
MethodInfo mi = m.getMethodInfo2(); MethodInfo mi = m.getMethodInfo2();
ClassFile cf = getClassFile2(); ClassFile cf = getClassFile2();
if (cf.getMethods().remove(mi)) { if (cf.getMethods().remove(mi)) {
methodsCache = CtMember.remove(methodsCache, m);
getMembers().remove(m);
memberRemoved = true; memberRemoved = true;
} }
else else
else { else {
classPool.writeClassfile(getName(), out); classPool.writeClassfile(getName(), out);
// to save memory // to save memory
eraseCache();
classfile = null;
// classfile = null;
} }


getCounter = 0;
wasFrozen = true; wasFrozen = true;
} }
catch (NotFoundException e) { catch (NotFoundException e) {
m.setAccessFlags(AccessFlag.STATIC); m.setAccessFlags(AccessFlag.STATIC);
m.setCodeAttribute(code.toCodeAttribute()); m.setCodeAttribute(code.toCodeAttribute());
cf.addMethod(m); cf.addMethod(m);
CtMember.Cache cache = hasMemberCache();
if (cache != null)
cache.addConstructor(new CtConstructor(m, this));
} }
else { else {
CodeAttribute codeAttr = m.getCodeAttribute(); CodeAttribute codeAttr = m.getCodeAttribute();

+ 0
- 1
src/main/javassist/CtConstructor.java Ver arquivo

public final class CtConstructor extends CtBehavior { public final class CtConstructor extends CtBehavior {
protected CtConstructor(MethodInfo minfo, CtClass declaring) { protected CtConstructor(MethodInfo minfo, CtClass declaring) {
super(declaring, minfo); super(declaring, minfo);
next = null;
} }


/** /**

+ 0
- 2
src/main/javassist/CtField.java Ver arquivo

throws CannotCompileException throws CannotCompileException
{ {
super(clazz); super(clazz);
next = null;
ClassFile cf = clazz.getClassFile2(); ClassFile cf = clazz.getClassFile2();
if (cf == null) if (cf == null)
throw new CannotCompileException("bad declaring class: " throw new CannotCompileException("bad declaring class: "
CtField(FieldInfo fi, CtClass clazz) { CtField(FieldInfo fi, CtClass clazz) {
super(clazz); super(clazz);
fieldInfo = fi; fieldInfo = fi;
next = null;
} }


/** /**

+ 98
- 42
src/main/javassist/CtMember.java Ver arquivo

* or a method. * or a method.
*/ */
public abstract class CtMember { public abstract class CtMember {
protected CtMember next; // for internal use
CtMember next; // for internal use
protected CtClass declaringClass; protected CtClass declaringClass;


protected CtMember(CtClass clazz) { declaringClass = clazz; }
/* Make a circular link of CtMembers declared in the
* same class so that they are garbage-collected together
* at the same time.
*/
static class Cache extends CtMember {
protected void extendToString(StringBuffer buffer) {}
public Object[] getAnnotations()
throws ClassNotFoundException { return null; }
public byte[] getAttribute(String name) { return null; }
public Object[] getAvailableAnnotations()
throws ClassNotFoundException { return null; }
public int getModifiers() { return 0; }
public String getName() { return null; }
public String getSignature() { return null; }
public void setAttribute(String name, byte[] data) {}
public void setModifiers(int mod) {}

private CtMember methodTail;
private CtMember consTail; // constructor tail
private CtMember fieldTail;


static CtMember append(CtMember list, CtMember previousTail, CtMember tail) {
tail.next = null;
if (list == null)
return tail;
else {
previousTail.next = tail;
return list;
Cache(CtClassType decl) {
super(decl);
methodTail = this;
consTail = this;
fieldTail = this;
fieldTail.next = this;
} }
}


static CtMember append(CtMember list, CtMember tail) {
tail.next = null;
if (list == null)
return tail;
else {
CtMember lst = list;
while (lst.next != null)
lst = lst.next;

lst.next = tail;
return list;
CtMember methodHead() { return this; }
CtMember lastMethod() { return methodTail; }
CtMember consHead() { return methodTail; } // may include a static initializer
CtMember lastCons() { return consTail; }
CtMember fieldHead() { return consTail; }
CtMember lastField() { return fieldTail; }

void addMethod(CtMember method) {
method.next = methodTail.next;
methodTail.next = method;
if (methodTail == consTail) {
consTail = method;
if (methodTail == fieldTail)
fieldTail = method;
}

methodTail = method;
} }
}


static int count(CtMember f) {
int n = 0;
while (f != null) {
++n;
f = f.next;
/* Both constructors and a class initializer.
*/
void addConstructor(CtMember cons) {
cons.next = consTail.next;
consTail.next = cons;
if (consTail == fieldTail)
fieldTail = cons;

consTail = cons;
} }


return n;
}
void addField(CtMember field) {
field.next = this; // or fieldTail.next
fieldTail.next = field;
fieldTail = field;
}

static int count(CtMember head, CtMember tail) {
int n = 0;
while (head != tail) {
n++;
head = head.next;
}

return n;
}

void remove(CtMember mem) {
CtMember m = this;
CtMember node;
while ((node = m.next) != this) {
if (node == mem) {
m.next = node.next;
if (node == methodTail)
methodTail = m;
else if (node == consTail)
consTail = m;
else if (node == fieldTail)
fieldTail = m;


static CtMember remove(CtMember list, CtMember m) {
CtMember top = list;
if (list == null)
return null;
else if (list == m)
return list.next;
else
while (list.next != null) {
if (list.next == m) {
list.next = list.next.next;
break; break;
} }

list = list.next;
else
m = m.next;
} }
}
}


return top;
protected CtMember(CtClass clazz) {
declaringClass = clazz;
next = null;
} }


final CtMember next() { return next; }

/**
* This method is invoked when setName() or replaceClassName()
* in CtClass is called.
*
* @see CtMethod#nameReplaced()
*/
void nameReplaced() {}

public String toString() { public String toString() {
StringBuffer buffer = new StringBuffer(getClass().getName()); StringBuffer buffer = new StringBuffer(getClass().getName());
buffer.append("@"); buffer.append("@");

+ 8
- 1
src/main/javassist/CtMethod.java Ver arquivo



CtMethod(MethodInfo minfo, CtClass declaring) { CtMethod(MethodInfo minfo, CtClass declaring) {
super(declaring, minfo); super(declaring, minfo);
next = null;
cachedStringRep = null; cachedStringRep = null;
} }


return getStringRep().hashCode(); return getStringRep().hashCode();
} }


/**
* This method is invoked when setName() or replaceClassName()
* in CtClass is called.
*/
void nameReplaced() {
cachedStringRep = null;
}

/* This method is also called by CtClassType.getMethods0(). /* This method is also called by CtClassType.getMethods0().
*/ */
final String getStringRep() { final String getStringRep() {

+ 0
- 1
src/main/javassist/CtNewClass.java Ver arquivo

boolean isInterface, CtClass superclass) { boolean isInterface, CtClass superclass) {
super(name, cp); super(name, cp);
wasChanged = true; wasChanged = true;
eraseCache();
String superName; String superName;
if (superclass == null) if (superclass == null)
superName = null; superName = null;

+ 3
- 0
src/main/javassist/CtNewWrappedMethod.java Ver arquivo

// a stack map is copied. rebuilding it is not needed. // a stack map is copied. rebuilding it is not needed.
classfile.addMethod(body); classfile.addMethod(body);
bodies.put(src, bodyname); bodies.put(src, bodyname);
CtMember.Cache cache = clazz.hasMemberCache();
if (cache != null)
cache.addMethod(new CtMethod(body, clazz));
} }


return bodyname; return bodyname;

+ 33
- 25
tutorial/tutorial.html Ver arquivo

to modify a class file that has been already loaded since the JVM does to modify a class file that has been already loaded since the JVM does
not allow reloading a class. not allow reloading a class.


<p>When Javassist freezes a <code>CtClass</code> object, it also
prunes the data structure contained in that object. To reduce memory
consumption, Javassist discards unnecessary attributes
<p>A frozen <code>CtClass</code> can be defrost so that
modifications of the class definition will be permitted. For example,

<ul><pre>
CtClasss cc = ...;
:
cc.writeFile();
cc.defrost();
cc.setSuperclass(...); // OK since the class is not frozen.
</pre></ul>

<p>After <code>defrost()</code> is called, the <code>CtClass</code>
object can be modified again.

<p>If <code>ClassPool.doPruning</code> is set to <code>true</code>,
then Javassist prunes the data structure contained
in a <code>CtClass</code> object
when Javassist freezes that object.
To reduce memory
consumption, pruning discards unnecessary attributes
(<code>attribute_info</code> structures) in that object. (<code>attribute_info</code> structures) in that object.
For example, <code>Code_attribute</code> structures (method bodies) For example, <code>Code_attribute</code> structures (method bodies)
are discarded. are discarded.
Thus, after a Thus, after a
<code>CtClass</code> object is pruned, the bytecode of a method is not <code>CtClass</code> object is pruned, the bytecode of a method is not
accessible although method names, signatures, and annotations
are still accessible.
accessible except method names, signatures, and annotations.
The pruned <code>CtClass</code> object cannot be defrost again.
The default value of <code>ClassPool.doPruning</code> is <code>false</code>.


<p>To disallow pruning a <code>CtClass</code>, <code>stopPruning()</code>
must be called in advance:
<p>To disallow pruning a particular <code>CtClass</code>,
<code>stopPruning()</code> must be called on that object in advance:


<ul><pre> <ul><pre>
CtClasss cc = ...; CtClasss cc = ...;
// cc is not pruned. // cc is not pruned.
</pre></ul> </pre></ul>


<p>If a <code>CtClass</code> is not pruned, it can be defrost so that
modifications of the class definition can be permitted. For example,

<ul><pre>
CtClasss cc = ...;
cc.stopPruning(true);
:
cc.writeFile();
cc.defrost();
cc.setSuperclass(...); // OK since the class is not frozen.
</pre></ul>

<p>To disallow pruning for all the <code>CtClass</code>es, set
<code>ClassPool.doPruning</code> to <code>false</code>.
<p>The <code>CtClass</code> object <code>cc</code> is not pruned.
Thus it can be defrost after <code>writeFile()</code> is called.


<ul><b>Note:</b> <ul><b>Note:</b>
While debugging, you might want to temporarily stop pruning and write a modified
class file to a disk drive. <code>debugWriteFile()</code> is a convenient method
for that purpose. It stops pruning, write a class file, defrost it, and turn
pruning on again (if it was initially on).
While debugging, you might want to temporarily stop pruning and freezing
and write a modified class file to a disk drive.
<code>debugWriteFile()</code> is a convenient method
for that purpose. It stops pruning, writes a class file, defrosts it,
and turns pruning on again (if it was initially on).
</ul> </ul>





<h4>Class search path</h4> <h4>Class search path</h4>


<p>The default <code>ClassPool</code> returned <p>The default <code>ClassPool</code> returned

Carregando…
Cancelar
Salvar