123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- /* *******************************************************************
- * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Common Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
- * Contributors:
- * Xerox/PARC initial implementation
- * ******************************************************************/
-
-
- package org.aspectj.weaver.bcel;
-
- import java.io.*;
- import java.lang.reflect.Modifier;
- import java.util.*;
-
- import org.apache.bcel.Constants;
- import org.apache.bcel.classfile.*;
- import org.apache.bcel.generic.*;
- import org.apache.bcel.util.ClassPath;
- import org.aspectj.weaver.*;
- import org.aspectj.util.CollectionUtil;
-
- public final class LazyClassGen {
-
- /** Emit disassembled class and newline to out */
- public static void disassemble(String path, String name, PrintStream out)
- throws IOException {
- if (null == out) {
- return;
- }
- //out.println("classPath: " + classPath);
-
- BcelWorld world = new BcelWorld(path);
-
- LazyClassGen clazz = new LazyClassGen((BcelObjectType) world.resolve(name));
- clazz.print(out);
- out.println();
- }
-
- private BcelObjectType myType; // XXX is not set for types we create
- private ClassGen myGen;
- private ConstantPoolGen constantPoolGen;
-
- private List /*LazyMethodGen*/
- methodGens = new ArrayList();
- private List /*LazyClassGen*/
- classGens = new ArrayList();
-
- private int childCounter = 0;
-
- public int getNewGeneratedNameTag() {
- return childCounter++;
- }
-
- private InstructionFactory fact;
- // ----
-
- public LazyClassGen(
- String class_name,
- String super_class_name,
- String file_name,
- int access_flags,
- String[] interfaces)
- {
- myGen = new ClassGen(class_name, super_class_name, file_name, access_flags, interfaces);
- constantPoolGen = myGen.getConstantPool();
- fact = new InstructionFactory(constantPoolGen);
- }
-
- //Non child type, so it comes from a real type in the world.
- public LazyClassGen(BcelObjectType myType) {
- myGen = new ClassGen(myType.getJavaClass());
- constantPoolGen = myGen.getConstantPool();
- fact = new InstructionFactory(constantPoolGen);
- this.myType = myType;
-
- Method[] methods = myGen.getMethods();
- for (int i = 0; i < methods.length; i++) {
- addMethodGen(new LazyMethodGen(methods[i], this));
- }
- }
-
- // public void addAttribute(Attribute i) {
- // myGen.addAttribute(i);
- // }
-
- // ----
-
- public String getInternalClassName() {
- return getConstantPoolGen().getConstantPool().getConstantString(
- myGen.getClassNameIndex(),
- Constants.CONSTANT_Class);
-
- }
-
- public File getPackagePath(File root) {
- String str = getInternalClassName();
- int index = str.lastIndexOf('/');
- if (index == -1)
- return root;
- return new File(root, str.substring(0, index));
- }
-
- public String getClassId() {
- String str = getInternalClassName();
- int index = str.lastIndexOf('/');
- if (index == -1)
- return str;
- return str.substring(index + 1);
- }
-
-
- public void addMethodGen(LazyMethodGen gen) {
- //assert gen.getClassName() == super.getClassName();
- methodGens.add(gen);
- }
-
- public List getMethodGens() {
- return Collections.unmodifiableList(methodGens);
-
- }
-
- private void writeBack() {
- addAjcInitializers();
-
-
- int len = methodGens.size();
- myGen.setMethods(new Method[0]);
- for (int i = 0; i < len; i++) {
- LazyMethodGen gen = (LazyMethodGen) methodGens.get(i);
- // we skip empty clinits
- if (isEmptyClinit(gen)) continue;
- myGen.addMethod(gen.getMethod());
- }
- }
-
- public JavaClass getJavaClass() {
- writeBack();
- return myGen.getJavaClass();
- }
-
- public void addGeneratedInner(LazyClassGen newClass) {
- classGens.add(newClass);
- }
-
- public void addInterface(TypeX typeX) {
- myGen.addInterface(typeX.getName());
- }
-
- // non-recursive, may be a bug, ha ha.
- private List getClassGens() {
- List ret = new ArrayList();
- ret.add(this);
- ret.addAll(classGens);
-
- return ret;
- }
-
-
- public List getChildClasses() {
- if (classGens.isEmpty()) return Collections.EMPTY_LIST;
- List ret = new ArrayList();
- for (Iterator i = classGens.iterator(); i.hasNext();) {
- LazyClassGen clazz = (LazyClassGen) i.next();
- byte[] bytes = clazz.getJavaClass().getBytes();
- String name = clazz.getName();
- int index = name.lastIndexOf('$');
- // XXX this could be bad, check use of dollar signs.
- name = name.substring(index+1);
- ret.add(new UnwovenClassFile.ChildClass(name, bytes));
- }
- return ret;
- }
-
- public String toString() {
- return toShortString();
- }
-
- public String toShortString() {
- String s =
- org.apache.bcel.classfile.Utility.accessToString(myGen.getAccessFlags(), true);
- if (s != "")
- s += " ";
- s += org.apache.bcel.classfile.Utility.classOrInterface(myGen.getAccessFlags());
- s += " ";
- s += myGen.getClassName();
- return s;
- }
-
- public String toLongString() {
- ByteArrayOutputStream s = new ByteArrayOutputStream();
- print(new PrintStream(s));
- return new String(s.toByteArray());
- }
-
- public void print() { print(System.out); }
-
- public void print(PrintStream out) {
- List classGens = getClassGens();
- for (Iterator iter = classGens.iterator(); iter.hasNext();) {
- LazyClassGen element = (LazyClassGen) iter.next();
- element.printOne(out);
- if (iter.hasNext()) out.println();
- }
- }
-
- private void printOne(PrintStream out) {
- out.print(toShortString());
- out.print(" extends ");
- out.print(
- org.apache.bcel.classfile.Utility.compactClassName(
- myGen.getSuperclassName(),
- false));
-
- int size = myGen.getInterfaces().length;
-
- if (size > 0) {
- out.print(" implements ");
- for (int i = 0; i < size; i++) {
- out.print(myGen.getInterfaceNames()[i]);
- if (i < size - 1)
- out.print(", ");
- }
- }
- out.print(":");
- out.println();
- // XXX make sure to pass types correctly around, so this doesn't happen.
- if (myType != null) {
- myType.printWackyStuff(out);
- }
- Field[] fields = myGen.getFields();
- for (int i = 0, len = fields.length; i < len; i++) {
- out.print(" ");
- out.println(fields[i]);
- }
- List methodGens = getMethodGens();
- for (Iterator iter = methodGens.iterator(); iter.hasNext();) {
- LazyMethodGen gen = (LazyMethodGen) iter.next();
- // we skip empty clinits
- if (isEmptyClinit(gen)) continue;
- gen.print(out);
- if (iter.hasNext()) out.println();
- }
- // out.println(" ATTRIBS: " + Arrays.asList(myGen.getAttributes()));
-
- out.println("end " + toShortString());
- }
-
- private boolean isEmptyClinit(LazyMethodGen gen) {
- if (!gen.getName().equals("<clinit>")) return false;
- //System.err.println("checking clinig: " + gen);
- InstructionHandle start = gen.getBody().getStart();
- while (start != null) {
- if (Range.isRangeHandle(start) || (start.getInstruction() instanceof RETURN)) {
- start = start.getNext();
- } else {
- return false;
- }
- }
-
- return true;
- }
-
- public ConstantPoolGen getConstantPoolGen() {
- return constantPoolGen;
- }
-
- public String getName() {
- return myGen.getClassName();
- }
-
- public WeaverStateKind getWeaverState() {
- WeaverStateKind kind = myType.getWeaverState();
- if (kind == null) return WeaverStateKind.Untouched;
- return kind;
- }
-
- public void setWeaverState(WeaverStateKind s) {
- Attribute[] attributes = myGen.getAttributes();
- if (attributes != null) {
- for (int i = attributes.length - 1; i >=0; i--) {
- Attribute a = attributes[i];
- if (a instanceof Unknown) {
- Unknown u = (Unknown) a;
- if (u.getName().equals(AjAttribute.WeaverState.AttributeName)) {
- myGen.removeAttribute(u);
- }
- }
- }
- }
- myGen.addAttribute(BcelAttributes.bcelAttribute(
- new AjAttribute.WeaverState(s),
- getConstantPoolGen()));
- }
-
- public InstructionFactory getFactory() {
- return fact;
- }
-
- public LazyMethodGen getStaticInitializer() {
- for (Iterator i = methodGens.iterator(); i.hasNext();) {
- LazyMethodGen gen = (LazyMethodGen) i.next();
- if (gen.getName().equals("<clinit>")) return gen;
- }
- LazyMethodGen clinit = new LazyMethodGen(
- Modifier.STATIC,
- Type.VOID,
- "<clinit>",
- new Type[0],
- CollectionUtil.NO_STRINGS,
- this);
- clinit.getBody().insert(getFactory().RETURN);
- methodGens.add(clinit);
- return clinit;
- }
-
- public LazyMethodGen getAjcClinit() {
- for (Iterator i = methodGens.iterator(); i.hasNext();) {
- LazyMethodGen gen = (LazyMethodGen) i.next();
- if (gen.getName().equals(NameMangler.AJC_CLINIT_NAME)) return gen;
- }
- throw new RuntimeException("unimplemented");
- // LazyMethodGen clinit = new LazyMethodGen(
- // Modifier.STATIC,
- // Type.VOID,
- // "<clinit>",
- // new Type[0],
- // CollectionUtil.NO_STRINGS,
- // this);
- // clinit.getBody().insert(getFactory().RETURN);
- // methodGens.add(clinit);
- // return clinit;
- }
-
-
-
- // reflective thisJoinPoint support
- Map/*BcelShadow, Field*/ tjpFields = new HashMap();
- public static final ObjectType tjpType =
- new ObjectType("org.aspectj.lang.JoinPoint");
- public static final ObjectType staticTjpType =
- new ObjectType("org.aspectj.lang.JoinPoint$StaticPart");
- private static final ObjectType sigType =
- new ObjectType("org.aspectj.lang.Signature");
- private static final ObjectType slType =
- new ObjectType("org.aspectj.lang.reflect.SourceLocation");
- private static final ObjectType factoryType =
- new ObjectType("org.aspectj.runtime.reflect.Factory");
- private static final ObjectType classType =
- new ObjectType("java.lang.Class");
-
- public Field getTjpField(BcelShadow shadow) {
- Field ret = (Field)tjpFields.get(shadow);
- if (ret != null) return ret;
-
- ret = new FieldGen(Modifier.STATIC | Modifier.PUBLIC | Modifier.FINAL,
- staticTjpType,
- "ajc$tjp_" + tjpFields.size(),
- getConstantPoolGen()).getField();
- addField(ret);
- tjpFields.put(shadow, ret);
- return ret;
- }
-
- private void addAjcInitializers() {
- if (tjpFields.size() == 0) return;
-
- InstructionList il = initializeAllTjps();
- getStaticInitializer().getBody().insert(il);
- }
-
-
- private InstructionList initializeAllTjps() {
- InstructionList list = new InstructionList();
- InstructionFactory fact = getFactory();
-
- // make a new factory
- list.append(fact.createNew(factoryType));
- list.append(fact.createDup(1));
-
- list.append(new PUSH(getConstantPoolGen(), getFileName()));
-
- // load the current Class object
- //XXX check that this works correctly for inners/anonymous
- list.append(new PUSH(getConstantPoolGen(), getClassName()));
- //XXX do we need to worry about the fact the theorectically this could throw
- //a ClassNotFoundException
- list.append(fact.createInvoke("java.lang.Class", "forName", classType,
- new Type[] {Type.STRING}, Constants.INVOKESTATIC));
-
- list.append(fact.createInvoke(factoryType.getClassName(), "<init>",
- Type.VOID, new Type[] {Type.STRING, classType},
- Constants.INVOKESPECIAL));
-
- list.append(fact.createStore(factoryType, 0));
-
- List entries = new ArrayList(tjpFields.entrySet());
- Collections.sort(entries, new Comparator() {
- public int compare(Object a, Object b) {
- Map.Entry ae = (Map.Entry) a;
- Map.Entry be = (Map.Entry) b;
- return ((Field) ae.getValue())
- .getName()
- .compareTo(((Field)be.getValue()).getName());
- }
- });
-
- for (Iterator i = entries.iterator(); i.hasNext(); ) {
- Map.Entry entry = (Map.Entry)i.next();
- initializeTjp(fact, list, (Field)entry.getValue(), (BcelShadow)entry.getKey());
- }
-
- return list;
- }
-
-
- private void initializeTjp(InstructionFactory fact, InstructionList list,
- Field field, BcelShadow shadow)
- {
- Member sig = shadow.getSignature();
- //ResolvedMember mem = shadow.getSignature().resolve(shadow.getWorld());
-
- // load the factory
- list.append(fact.createLoad(factoryType, 0));
-
- // load the kind
- list.append(new PUSH(getConstantPoolGen(), shadow.getKind().getName()));
-
- // create the signature
- list.append(fact.createLoad(factoryType, 0));
- list.append(new PUSH(getConstantPoolGen(), sig.getSignatureString(shadow.getWorld())));
- list.append(fact.createInvoke(factoryType.getClassName(),
- sig.getSignatureMakerName(),
- new ObjectType(sig.getSignatureType()),
- new Type[] { Type.STRING },
- Constants.INVOKEVIRTUAL));
-
- //XXX should load source location from shadow
- list.append(Utility.createConstant(fact, shadow.getSourceLine()));
-
-
- list.append(fact.createInvoke(factoryType.getClassName(),
- "makeSJP", staticTjpType,
- new Type[] { Type.STRING, sigType, Type.INT},
- Constants.INVOKEVIRTUAL));
-
- // put it in the field
- list.append(fact.createFieldAccess(getClassName(), field.getName(),
- staticTjpType, Constants.PUTSTATIC));
- }
-
-
- public BcelObjectType getType() {
- return myType;
- }
-
- public String getFileName() {
- return myGen.getFileName();
- }
-
- public void addField(Field field) {
- myGen.addField(field);
- }
-
- public String getClassName() {
- return myGen.getClassName();
- }
-
- public boolean isInterface() {
- return myGen.isInterface();
- }
-
- public LazyMethodGen getLazyMethodGen(Member m) {
- return getLazyMethodGen(m.getName(), m.getSignature());
- }
-
- public LazyMethodGen getLazyMethodGen(String name, String signature) {
- for (Iterator i = methodGens.iterator(); i.hasNext();) {
- LazyMethodGen gen = (LazyMethodGen) i.next();
- if (gen.getName().equals(name) && gen.getSignature().equals(signature))
- return gen;
- }
- throw new BCException("Class " + this.getName() + " does not have a method "
- + name + " with signature " + signature);
- }
- }
|