package hep.io.root.core; import hep.io.root.RootClass; import hep.io.root.RootMember; import hep.io.root.interfaces.TBranch; import hep.io.root.interfaces.TLeaf; import hep.io.root.interfaces.TObjArray; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.bcel.Constants; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.generic.ArrayType; import org.apache.bcel.generic.BranchHandle; import org.apache.bcel.generic.ClassGen; import org.apache.bcel.generic.ConstantPoolGen; import org.apache.bcel.generic.FieldGen; import org.apache.bcel.generic.IFNONNULL; import org.apache.bcel.generic.Instruction; import org.apache.bcel.generic.InstructionConstants; import org.apache.bcel.generic.InstructionFactory; import org.apache.bcel.generic.InstructionList; import org.apache.bcel.generic.MethodGen; import org.apache.bcel.generic.ObjectType; import org.apache.bcel.generic.Type; /** * Creates a class which extends Clones2 and which represents a TClonesArray * read in split mode. * Clones2Builder is used for Root 3.01 and later. * @see hep.io.root.core.Clones2 * @author tonyj * @version $Id: Clones2Builder.java 13618 2009-04-10 00:02:54Z tonyj $ */ public class Clones2Builder implements ClassBuilder, Constants { private static NameMangler nameMangler = NameMangler.instance(); private Map lMap; private TBranch branch; private boolean optimize; public Clones2Builder(TBranch branch) { this.branch = branch; } public String getStem() { return "hep.io.root.clones2"; } public JavaClass build(GenericRootClass klass) { optimize = (klass.getStreamerInfo().getBits() & (1 << 12)) == 0; //System.out.println("bits=" + Integer.toHexString(klass.getStreamerInfo().getBits()) + " optimize=" + optimize); String className = nameMangler.mangleFullClassName(getStem(),klass.getClassName()); ClassGen cg = new ClassGen(className, "hep/io/root/core/Clones2", "<generated>", ACC_PUBLIC | ACC_SUPER, null); ConstantPoolGen cp = cg.getConstantPool(); InstructionList il = new InstructionList(); InstructionFactory factory = new InstructionFactory(cg); cg.addEmptyConstructor(ACC_PUBLIC); // Build the complete list of superclasses List sup = new ArrayList(); RootClass[] superClasses = klass.getSuperClasses(); iterativelyAdd(sup, superClasses); sup.add(klass); // Loop over all the leafs, and build a hashtable from name->leaf Map nameMap = new HashMap(); TObjArray branches = branch.getBranches(); for (Iterator j = branches.iterator(); j.hasNext();) { TBranch br = (TBranch) j.next(); TObjArray leaves = br.getLeaves(); branch: for (Iterator i = leaves.iterator(); i.hasNext();) { Object leaf = i.next(); String name = ((TLeaf) leaf).getName(); int pos = name.indexOf('['); if (pos > 0) name = name.substring(0, pos); if (name.endsWith("_")) name = name.substring(0, name.length() - 1); pos = name.indexOf("."); if (pos > 0) name = name.substring(pos + 1); nameMap.put(name, leaf); } } lMap = new HashMap(); // Loop over the members and try to find the matching leaf for (Iterator j = sup.iterator(); j.hasNext();) { RootClass k = (RootClass) j.next(); RootMember[] members = k.getMembers(); for (int i = 0; i < members.length; i++) { BasicMember member = (BasicMember) members[i]; String name = member.getName(); if (name.endsWith("_")) name = name.substring(0, name.length() - 1); Object leaf = nameMap.remove(name); if (leaf == null) { System.out.println("Warning: no leaf for " + member.getName()); } else { lMap.put(member, leaf); } } } // Check for any left over leafs for (Iterator i = nameMap.keySet().iterator(); i.hasNext();) { System.out.println("Warning: unused leaf " + i.next()); } // Generate the fields for (Iterator i = sup.iterator(); i.hasNext();) generateFields((RootClass) i.next(), cp, cg); // Generate the static fields for (Iterator i = sup.iterator(); i.hasNext();) generateStaticFields((RootClass) i.next(), cp, cg); // Generate the accessor methods for (Iterator i = sup.iterator(); i.hasNext();) generateMethods((RootClass) i.next(), cp, il, factory, cg, className); // Generate the createClone method { String cloneName = nameMangler.mangleFullClassName("hep.io.root.clone2",klass.getClassName()); MethodGen mg = new MethodGen(ACC_PUBLIC, new ObjectType("hep.io.root.core.Clone2"), null, null, "createClone", className, il, cp); il.append((Instruction) factory.createNew(new ObjectType(cloneName))); il.append(InstructionConstants.DUP); il.append(factory.createInvoke(cloneName, "<init>", Type.VOID, Type.NO_ARGS, INVOKESPECIAL)); il.append(InstructionConstants.ARETURN); mg.setMaxStack(); mg.setMaxLocals(); cg.addMethod(mg.getMethod()); il.dispose(); } // Generate the clearCache method { MethodGen mg = new MethodGen(ACC_PROTECTED, Type.VOID, null, null, "clearCache", className, il, cp); for (Iterator j = sup.iterator(); j.hasNext();) { RootClass k = (RootClass) j.next(); RootMember[] members = k.getMembers(); for (int i = 0; i < members.length; i++) { BasicMember member = (BasicMember) members[i]; TLeaf leaf = (TLeaf) lMap.get(member); Type type = member.getJavaType(); Type arrayType = new ArrayType(type, 1); il.append(InstructionConstants.ALOAD_0); il.append(InstructionConstants.ACONST_NULL); il.append(factory.createPutField(className, member.getName(), arrayType)); } } il.append(InstructionConstants.RETURN); mg.setMaxStack(); mg.setMaxLocals(); cg.addMethod(mg.getMethod()); } il.dispose(); return cg.getJavaClass(); } public void populateStatics(Class hollowClass, RootClassFactory factory) { try { // Loop over the leaves for (Iterator i = lMap.entrySet().iterator(); i.hasNext();) { Map.Entry entry = (Map.Entry) i.next(); BasicMember member = (BasicMember) entry.getKey(); Object l = entry.getValue(); java.lang.reflect.Field field = hollowClass.getField(member.getName() + "Leaf"); field.set(null, l); } } catch (Exception x) { throw new RuntimeException("Error populating statics ",x); } } private void generateFields(RootClass k, ConstantPoolGen cp, ClassGen cg) { if (k.getClassName().equals("TObject") && optimize) return; RootMember[] members = k.getMembers(); for (int i = 0; i < members.length; i++) { BasicMember member = (BasicMember) members[i]; Type type = ((BasicMember) members[i]).getJavaType(); type = new ArrayType(type, 1); FieldGen fg = new FieldGen(ACC_PRIVATE, type, members[i].getName(), cp); cg.addField(fg.getField()); } } private void generateMethods(RootClass k, ConstantPoolGen cp, InstructionList il, InstructionFactory factory, ClassGen cg, String className) { RootMember[] members = k.getMembers(); for (int i = 0; i < members.length; i++) { BasicMember member = (BasicMember) members[i]; TLeaf leaf = (TLeaf) lMap.get(member); if (leaf == null) continue; String leafClassName = leaf.getClass().getName(); Type type = member.getJavaType(); Type arrayType = new ArrayType(type, 1); MethodGen mg = new MethodGen(ACC_PUBLIC, type, new Type[] { Type.INT }, new String[] { "index" }, nameMangler.mangleMember(member.getName()), className, il, cp); il.append(InstructionConstants.ALOAD_0); il.append(factory.createGetField(className, member.getName(), arrayType)); il.append(InstructionFactory.DUP); BranchHandle bh = il.append(new IFNONNULL(null)); il.append(InstructionFactory.POP); il.append(factory.createGetStatic(className, member.getName() + "Leaf", new ObjectType(leafClassName))); il.append(InstructionConstants.ALOAD_0); il.append(factory.createGetField("hep.io.root.core.Clones2", "hollowIndex", Type.LONG)); // BasicRootClass varClass = (BasicRootClass) member.getType(); il.append(factory.createInvoke(leafClassName, "setPosition", new ObjectType("hep.io.root.core.RootInput"), new Type[] { Type.LONG }, INVOKEVIRTUAL)); il.append(InstructionConstants.ALOAD_0); il.append(factory.createGetField("hep.io.root.core.Clones2", "size", Type.INT)); il.append((Instruction) factory.createNewArray(type, (short) 1)); il.append(InstructionConstants.DUP_X1); il.append(factory.createInvoke("hep.io.root.core.RootInput", "readFixedArray", Type.VOID, new Type[] { arrayType }, INVOKEINTERFACE)); il.append(InstructionConstants.DUP); il.append(InstructionConstants.ALOAD_0); il.append(InstructionConstants.SWAP); il.append(factory.createPutField(className, member.getName(), arrayType)); bh.setTarget(il.append(InstructionConstants.ILOAD_1)); il.append(InstructionFactory.createArrayLoad(type)); il.append(InstructionFactory.createReturn(type)); mg.setMaxStack(); mg.setMaxLocals(); cg.addMethod(mg.getMethod()); il.dispose(); } } private void generateStaticFields(RootClass k, ConstantPoolGen cp, ClassGen cg) { RootMember[] members = k.getMembers(); for (int i = 0; i < members.length; i++) { BasicMember member = (BasicMember) members[i]; TLeaf leaf = (TLeaf) lMap.get(member); if (leaf != null) { Type type = new ObjectType(leaf.getClass().getName()); FieldGen fg = new FieldGen(ACC_PUBLIC | ACC_STATIC, type, member.getName() + "Leaf", cp); cg.addField(fg.getField()); } } } private void iterativelyAdd(List list, RootClass[] superClasses) { for (int i = 0; i < superClasses.length; i++) { RootClass[] supsup = superClasses[i].getSuperClasses(); iterativelyAdd(list, supsup); list.add(superClasses[i]); } } }