/* This file is part of JOP, the Java Optimized Processor see <http://www.jopdesign.com/> Copyright (C) 2005-2008, Martin Schoeberl (martin@jopdesign.com) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * Created on 04.06.2005 * */ package com.jopdesign.build; import org.apache.bcel.Constants; import org.apache.bcel.classfile.Constant; import org.apache.bcel.classfile.ConstantClass; import org.apache.bcel.classfile.ConstantFieldref; import org.apache.bcel.classfile.ConstantInterfaceMethodref; import org.apache.bcel.classfile.ConstantMethodref; import org.apache.bcel.classfile.ConstantNameAndType; import org.apache.bcel.classfile.ConstantPool; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.Method; import org.apache.bcel.generic.CPInstruction; import org.apache.bcel.generic.ConstantPoolGen; import org.apache.bcel.generic.InstructionHandle; import org.apache.bcel.generic.InstructionList; import org.apache.bcel.generic.MethodGen; import org.apache.bcel.util.InstructionFinder; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; /** * Find a correct order of static class initializers (<clinit>) * @author martin * @deprecated Use ClinitOrder from common.tools with new *Info classes instead */ public class OldClinitOrder extends AppVisitor { Map clinit = new HashMap(); public OldClinitOrder(OldAppInfo jz) { super(jz); } public void visitJavaClass(JavaClass clazz) { super.visitJavaClass(clazz); OldMethodInfo mi = getCli().getMethodInfo(OldAppInfo.clinitSig); if (mi!=null) { Set depends = findDependencies(getCli(), mi, false); clinit.put(getCli(), depends); } } private Set findDependencies(OldClassInfo cli, OldMethodInfo mi, boolean inRec) { // System.out.println("find dep. in "+cli.clazz.getClassName()+":"+mi.getMethod().getName()); Method method = mi.getMethod(); Set depends = new HashSet(); if (method.isNative() || method.isAbstract()) { // nothing to do // or should we look for all possible subclasses on // abstract.... or in general also all possible // subclasses???? :-( return depends; } ConstantPool cpool = cli.clazz.getConstantPool(); ConstantPoolGen cpoolgen = new ConstantPoolGen(cpool); MethodGen mg = new MethodGen(method, cli.clazz.getClassName(), cpoolgen); InstructionList il = mg.getInstructionList(); InstructionFinder f = new InstructionFinder(il); // find instructions that access the constant pool // collect all indices to constants in ClassInfo String cpInstr = "CPInstruction"; for(Iterator it = f.search(cpInstr); it.hasNext(); ) { InstructionHandle[] match = (InstructionHandle[])it.next(); InstructionHandle first = match[0]; CPInstruction ii = (CPInstruction)first.getInstruction(); int idx = ii.getIndex(); Constant co = cpool.getConstant(idx); ConstantClass cocl = null; Set addDepends = null; String clname; OldClassInfo clinfo; OldMethodInfo minfo; switch(co.getTag()) { case Constants.CONSTANT_Class: cocl = (ConstantClass) co; clname = cocl.getBytes(cpool).replace('/','.'); clinfo = (OldClassInfo) ai.cliMap.get(clname); if (clinfo!=null) { minfo = clinfo.getMethodInfo("<init>()V"); if (minfo!=null) { addDepends = findDependencies(clinfo, minfo, true); } } // check for all sub classes when no going up the hierarchy // if (!inRec) { // Object[] y = clinfo.getSubClasses().toArray(); // for (int i=0; i<y.length; ++i) { // clinfo = (ClassInfo) y[i]; // minfo = clinfo.getMethodInfo("<init>()V"); // if (minfo!=null) { // System.out.println("known sub classes with this method"); // System.out.println(((ClassInfo) y[i]).clazz.getClassName()); // } // } // } break; case Constants.CONSTANT_InterfaceMethodref: cocl = (ConstantClass) cpool.getConstant(((ConstantInterfaceMethodref) co).getClassIndex()); break; case Constants.CONSTANT_Methodref: cocl = (ConstantClass) cpool.getConstant(((ConstantMethodref) co).getClassIndex()); clname = cocl.getBytes(cpool).replace('/','.'); clinfo = (OldClassInfo) ai.cliMap.get(clname); int sigidx = ((ConstantMethodref) co).getNameAndTypeIndex(); ConstantNameAndType signt = (ConstantNameAndType) cpool.getConstant(sigidx); String sigstr = signt.getName(cpool)+signt.getSignature(cpool); if (clinfo!=null) { minfo = clinfo.getMethodInfo(sigstr); if (minfo!=null) { addDepends = findDependencies(clinfo, minfo, true); } } // check for all sub classes when no going up the hierarchy // if (!inRec) { // Object[] x = clinfo.getSubClasses().toArray(); // for (int i=0; i<x.length; ++i) { // clinfo = (ClassInfo) x[i]; // minfo = clinfo.getMethodInfo(sigstr); // if (minfo!=null) { // System.out.println("known sub classes with this method"); // System.out.println(((ClassInfo) x[i]).clazz.getClassName()); // } // } // } break; case Constants.CONSTANT_Fieldref: cocl = (ConstantClass) cpool.getConstant(((ConstantFieldref) co).getClassIndex()); break; } if (cocl!=null) { clname = cocl.getBytes(cpool).replace('/','.'); OldClassInfo clinf = (OldClassInfo) ai.cliMap.get(clname); if (clinf!=null) { if (clinf.getMethodInfo(OldAppInfo.clinitSig)!=null) { // don't add myself as dependency if (clinf!=cli) { depends.add(clinf); } } } } if (addDepends!=null) { Iterator itAddDep = addDepends.iterator(); while (itAddDep.hasNext()) { OldClassInfo addCli = (OldClassInfo) itAddDep.next(); if (addCli==cli) { throw new Error("cyclic indirect <clinit> dependency"); } depends.add(addCli); } } } il.dispose(); return depends; } /** * Print the dependency for debugging. Not used at the moment. * */ private void printDependency() { Set cliSet = clinit.keySet(); Iterator itCliSet = cliSet.iterator(); while (itCliSet.hasNext()) { OldClassInfo clinf = (OldClassInfo) itCliSet.next(); System.out.println("Class "+clinf.clazz.getClassName()); Set depends = (Set) clinit.get(clinf); Iterator it = depends.iterator(); while(it.hasNext()) { OldClassInfo clf = (OldClassInfo) it.next(); System.out.println("\tdepends "+clf.clazz.getClassName()); } } } /** * Find a 'correct' oder for the static <clinit>. * Throws an error on cyclic dependencies. * * @return the ordered list of classes */ public List findOrder() { printDependency(); Set cliSet = clinit.keySet(); List order = new LinkedList(); int maxIter = cliSet.size(); // maximum loop bound detects cyclic dependency for (int i=0; i<maxIter && cliSet.size()!=0; ++i) { Iterator itCliSet = cliSet.iterator(); while (itCliSet.hasNext()) { OldClassInfo clinf = (OldClassInfo) itCliSet.next(); Set depends = (Set) clinit.get(clinf); if (depends.size()==0) { order.add(clinf); // check all depends sets and remove the added // element (a leave in the dependent tree Iterator itCliSetInner = clinit.keySet().iterator(); while (itCliSetInner.hasNext()) { OldClassInfo clinfInner = (OldClassInfo) itCliSetInner.next(); Set dep = (Set) clinit.get(clinfInner); dep.remove(clinf); } itCliSet.remove(); } } } if (cliSet.size()!=0) { printDependency(); throw new Error("Cyclic dependency in <clinit>"); } return order; } }