package hep.io.root.core;
import hep.io.root.RootClass;
import hep.io.root.RootMember;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.FieldGen;
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.PUSH;
import org.apache.bcel.generic.RETURN;
import org.apache.bcel.generic.Type;
/**
* Creates a class which extends Clones and which represents a set of clones
* read in split mode. Note when optimization is enabled in the Root file,
* multiple logical fields may be read into a single field. Suitable offsets
* are automatically built into the corresponding Clone for accessing data
* from these fields.
* @see hep.io.root.core.Clones
* @author tonyj
* @version $Id: ClonesBuilder.java 13618 2009-04-10 00:02:54Z tonyj $
*/
class ClonesBuilder implements ClassBuilder, Constants
{
private static NameMangler nameMangler = NameMangler.instance();
private boolean optimize;
public String getStem()
{
return "hep.io.root.clones";
}
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/Clones", "<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);
// Generate the fields
for (Iterator i = sup.iterator(); i.hasNext();)
generateFields((RootClass) i.next(), cp, cg);
// Generate the streamer method
MethodGen mg = new MethodGen(ACC_PUBLIC, Type.VOID, new Type[]
{
new ObjectType("hep/io/root/core/RootInput"), Type.INT
}, new String[] { "in", "nClones" }, "read", className, il, cp);
mg.addException("java/io/IOException");
for (Iterator i = sup.iterator(); i.hasNext();)
generateStreamer((RootClass) i.next(), cp, il, factory, className);
il.append(new RETURN());
mg.setMaxStack();
mg.setMaxLocals();
cg.addMethod(mg.getMethod());
il.dispose();
return cg.getJavaClass();
}
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];
if (optimize && ((i + 1) < members.length) && (member.getArrayDim() == 0) && member.getJavaType().equals(((BasicMember) members[i + 1]).getJavaType())) {}
else
{
Type type = ((BasicMember) members[i]).getJavaType();
type = new ArrayType(type, 1);
FieldGen fg = new FieldGen(ACC_PUBLIC, type, members[i].getName(), cp);
cg.addField(fg.getField());
}
}
}
private void generateStreamer(RootClass k, ConstantPoolGen cp, InstructionList il, InstructionFactory factory, String className)
{
if (k.getClassName().equals("TObject") && optimize)
return;
RootMember[] members = k.getMembers();
int multiplier = 1;
for (int i = 0; i < members.length; i++)
{
BasicMember member = (BasicMember) members[i];
if (optimize && ((i + 1) < members.length) && (member.getArrayDim() == 0) && member.getJavaType().equals(((BasicMember) members[i + 1]).getJavaType()))
{
multiplier++;
}
else
{
Type type = member.getJavaType();
Type arrayType = new ArrayType(type, 1);
il.append(InstructionConstants.ALOAD_0);
il.append(InstructionConstants.ALOAD_1);
il.append(InstructionConstants.ILOAD_2); //length
if (multiplier > 1)
{
il.append(new PUSH(cp, multiplier));
il.append(InstructionConstants.IMUL);
}
String varCounter = member.getVarCounter();
if (varCounter == null)
{
for (int j = 0; j < member.getArrayDim(); j++)
il.append(new PUSH(cp, member.getMaxIndex(j)));
il.append((Instruction) factory.createNewArray(((BasicRootClass) member.getType()).getJavaType(), (short) (member.getArrayDim() + 1)));
il.append(InstructionConstants.DUP_X1);
if (member.getArrayDim() == 0)
{
if (type instanceof ObjectType)
{
il.append(new PUSH(cp,member.getType().getClassName()));
il.append(factory.createInvoke("hep.io.root.core.IOUtils", "readFixedArray", Type.VOID, new Type[]
{
RootType.ROOTINPUT, new ArrayType(Type.OBJECT, 1), RootType.STRING
}, INVOKESTATIC));
}
else
{
il.append(factory.createInvoke("hep.io.root.core.RootInput", "readFixedArray", Type.VOID, new Type[]
{
arrayType
}, INVOKEINTERFACE));
}
}
else
{
il.append(factory.createInvoke("hep.io.root.core.RootInput", "readMultiArray", Type.VOID, new Type[]
{
new ArrayType(Type.OBJECT, 1)
}, INVOKEINTERFACE));
}
}
else
{
il.append((Instruction) factory.createNewArray(type, (short)1));
il.append(InstructionConstants.DUP_X1);
il.append(InstructionConstants.ALOAD_0);
il.append(factory.createFieldAccess(className, varCounter, RootType.INTARRAY, Constants.GETFIELD));
il.append(factory.createInvoke("hep.io.root.core.IOUtils", "readVariableMultiArray", Type.VOID, new Type[]
{
RootType.ROOTINPUT,arrayType,RootType.INTARRAY
}, INVOKESTATIC));
}
il.append(factory.createPutField(className, member.getName(), arrayType));
multiplier = 1;
}
}
}
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]);
}
}
}