/**
* Speedo: an implementation of JDO compliant personality on top of JORM generic
* I/O sub-system.
* Copyright (C) 2001-2005 France Telecom R&D
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
*
* Contact: speedo@objectweb.org
*
* Authors: S.Chassande-Barrioz.
*
*/
package org.objectweb.speedo.generation.enhancer.common;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.CodeAdapter;
import org.objectweb.asm.CodeVisitor;
import org.objectweb.asm.Constants;
import org.objectweb.speedo.lib.Personality;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import java.util.ArrayList;
import java.util.List;
/**
* ASM visitor cleaning a visited class to merge to another:
* <ul>
* <li>keep only one "class$" method</li>
* <li>rename a static section in order to agregate all at the end</li>
* <li>do not merge abstract method</li>
* <li>do not merge constructor</li>
* <li>do not merge this method</li>
* </ul>
*
* @author S.Chassande-Barrioz
*/
public class MergedClassModifier extends LoggedClassAdapter {
private String classToWrite;
private String oldClass;
boolean hasDotClassMethod;
List methodNames;
/**
* Builds the visitor
*
* @param classtowrite
* is the final name of the class to write
* @param oldclassName is the old name of the class.
*/
public MergedClassModifier(final ClassVisitor classVisitor,
final String classtowrite,
final String oldclassName,
final Logger logger,
final Personality p) {
super(classVisitor, p, logger);
this.classToWrite = getJVMClassName(classtowrite);
this.oldClass = getJVMClassName(oldclassName);
this.methodNames = new ArrayList();
}
// IMPLEMENTATION OF THE ClassVisitor INTERFACE //
// ---------------------------------------------//
public CodeVisitor visitMethod(final int access, final String name,
final String desc, final String[] exceptions, final Attribute attrs) {
String mn = name;
if ("class$".equals(name)) {
// keep only one "class$" method
if (hasDotClassMethod) {
// remove useless .class static method
return null;
} else {
// First .class static method
hasDotClassMethod = true;
}
} else if ("<clinit>".equals(name)) {
// rename a static section in order to agregate all at the end
mn = "clinit$" + methodNames.size();
methodNames.add(mn);
if (debug) {
logger
.log(BasicLevel.DEBUG, "rename a static section to "
+ mn);
}
} else if ((access & Constants.ACC_ABSTRACT) != 0) {
// do not merge abstract method
return null;
} else if (name.equals("<init>")) {
// do not merge constructor
return null;
} else if (name.equals("this")) {
// do not merge this method
return null;
}
//Modifies instructions that reference the old class.
CodeVisitor mv = cv.visitMethod(access, mn, desc, exceptions, attrs);
if (mv != null) {
mv = new CodeRenamer(mv, oldClass, classToWrite);
}
return mv;
}
public void visitEnd() {
// Merge the static initializer
if (methodNames.size() > 0) {
CodeVisitor mv = this.cv.visitMethod(Constants.ACC_STATIC,
"<clinit>", "()V", null, null);
for (int i = 0; i < methodNames.size(); i++) {
String methodName = (String) methodNames.get(i);
mv.visitMethodInsn(Constants.INVOKESTATIC, classToWrite,
methodName, "()V");
}
mv.visitInsn(Constants.RETURN);
}
super.visitEnd();
}
}