You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LazyClassGen.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Common Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * Contributors:
  10. * Xerox/PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.weaver.bcel;
  13. import java.io.*;
  14. import java.lang.reflect.Modifier;
  15. import java.util.*;
  16. import org.apache.bcel.Constants;
  17. import org.apache.bcel.classfile.*;
  18. import org.apache.bcel.generic.*;
  19. import org.apache.bcel.util.ClassPath;
  20. import org.aspectj.weaver.*;
  21. import org.aspectj.util.CollectionUtil;
  22. public final class LazyClassGen {
  23. /** Emit disassembled class and newline to out */
  24. public static void disassemble(String path, String name, PrintStream out)
  25. throws IOException {
  26. if (null == out) {
  27. return;
  28. }
  29. //out.println("classPath: " + classPath);
  30. BcelWorld world = new BcelWorld(path);
  31. LazyClassGen clazz = new LazyClassGen((BcelObjectType) world.resolve(name));
  32. clazz.print(out);
  33. out.println();
  34. }
  35. private BcelObjectType myType; // XXX is not set for types we create
  36. private ClassGen myGen;
  37. private ConstantPoolGen constantPoolGen;
  38. private List /*LazyMethodGen*/
  39. methodGens = new ArrayList();
  40. private List /*LazyClassGen*/
  41. classGens = new ArrayList();
  42. private int childCounter = 0;
  43. public int getNewGeneratedNameTag() {
  44. return childCounter++;
  45. }
  46. private InstructionFactory fact;
  47. // ----
  48. public LazyClassGen(
  49. String class_name,
  50. String super_class_name,
  51. String file_name,
  52. int access_flags,
  53. String[] interfaces)
  54. {
  55. myGen = new ClassGen(class_name, super_class_name, file_name, access_flags, interfaces);
  56. constantPoolGen = myGen.getConstantPool();
  57. fact = new InstructionFactory(constantPoolGen);
  58. }
  59. //Non child type, so it comes from a real type in the world.
  60. public LazyClassGen(BcelObjectType myType) {
  61. myGen = new ClassGen(myType.getJavaClass());
  62. constantPoolGen = myGen.getConstantPool();
  63. fact = new InstructionFactory(constantPoolGen);
  64. this.myType = myType;
  65. Method[] methods = myGen.getMethods();
  66. for (int i = 0; i < methods.length; i++) {
  67. addMethodGen(new LazyMethodGen(methods[i], this));
  68. }
  69. }
  70. // public void addAttribute(Attribute i) {
  71. // myGen.addAttribute(i);
  72. // }
  73. // ----
  74. public String getInternalClassName() {
  75. return getConstantPoolGen().getConstantPool().getConstantString(
  76. myGen.getClassNameIndex(),
  77. Constants.CONSTANT_Class);
  78. }
  79. public File getPackagePath(File root) {
  80. String str = getInternalClassName();
  81. int index = str.lastIndexOf('/');
  82. if (index == -1)
  83. return root;
  84. return new File(root, str.substring(0, index));
  85. }
  86. public String getClassId() {
  87. String str = getInternalClassName();
  88. int index = str.lastIndexOf('/');
  89. if (index == -1)
  90. return str;
  91. return str.substring(index + 1);
  92. }
  93. public void addMethodGen(LazyMethodGen gen) {
  94. //assert gen.getClassName() == super.getClassName();
  95. methodGens.add(gen);
  96. }
  97. public List getMethodGens() {
  98. return Collections.unmodifiableList(methodGens);
  99. }
  100. private void writeBack() {
  101. addAjcInitializers();
  102. int len = methodGens.size();
  103. myGen.setMethods(new Method[0]);
  104. for (int i = 0; i < len; i++) {
  105. LazyMethodGen gen = (LazyMethodGen) methodGens.get(i);
  106. // we skip empty clinits
  107. if (isEmptyClinit(gen)) continue;
  108. myGen.addMethod(gen.getMethod());
  109. }
  110. }
  111. public JavaClass getJavaClass() {
  112. writeBack();
  113. return myGen.getJavaClass();
  114. }
  115. public void addGeneratedInner(LazyClassGen newClass) {
  116. classGens.add(newClass);
  117. }
  118. public void addInterface(TypeX typeX) {
  119. myGen.addInterface(typeX.getName());
  120. }
  121. // non-recursive, may be a bug, ha ha.
  122. private List getClassGens() {
  123. List ret = new ArrayList();
  124. ret.add(this);
  125. ret.addAll(classGens);
  126. return ret;
  127. }
  128. public List getChildClasses() {
  129. if (classGens.isEmpty()) return Collections.EMPTY_LIST;
  130. List ret = new ArrayList();
  131. for (Iterator i = classGens.iterator(); i.hasNext();) {
  132. LazyClassGen clazz = (LazyClassGen) i.next();
  133. byte[] bytes = clazz.getJavaClass().getBytes();
  134. String name = clazz.getName();
  135. int index = name.lastIndexOf('$');
  136. // XXX this could be bad, check use of dollar signs.
  137. name = name.substring(index+1);
  138. ret.add(new UnwovenClassFile.ChildClass(name, bytes));
  139. }
  140. return ret;
  141. }
  142. public String toString() {
  143. return toShortString();
  144. }
  145. public String toShortString() {
  146. String s =
  147. org.apache.bcel.classfile.Utility.accessToString(myGen.getAccessFlags(), true);
  148. if (s != "")
  149. s += " ";
  150. s += org.apache.bcel.classfile.Utility.classOrInterface(myGen.getAccessFlags());
  151. s += " ";
  152. s += myGen.getClassName();
  153. return s;
  154. }
  155. public String toLongString() {
  156. ByteArrayOutputStream s = new ByteArrayOutputStream();
  157. print(new PrintStream(s));
  158. return new String(s.toByteArray());
  159. }
  160. public void print() { print(System.out); }
  161. public void print(PrintStream out) {
  162. List classGens = getClassGens();
  163. for (Iterator iter = classGens.iterator(); iter.hasNext();) {
  164. LazyClassGen element = (LazyClassGen) iter.next();
  165. element.printOne(out);
  166. if (iter.hasNext()) out.println();
  167. }
  168. }
  169. private void printOne(PrintStream out) {
  170. out.print(toShortString());
  171. out.print(" extends ");
  172. out.print(
  173. org.apache.bcel.classfile.Utility.compactClassName(
  174. myGen.getSuperclassName(),
  175. false));
  176. int size = myGen.getInterfaces().length;
  177. if (size > 0) {
  178. out.print(" implements ");
  179. for (int i = 0; i < size; i++) {
  180. out.print(myGen.getInterfaceNames()[i]);
  181. if (i < size - 1)
  182. out.print(", ");
  183. }
  184. }
  185. out.print(":");
  186. out.println();
  187. // XXX make sure to pass types correctly around, so this doesn't happen.
  188. if (myType != null) {
  189. myType.printWackyStuff(out);
  190. }
  191. Field[] fields = myGen.getFields();
  192. for (int i = 0, len = fields.length; i < len; i++) {
  193. out.print(" ");
  194. out.println(fields[i]);
  195. }
  196. List methodGens = getMethodGens();
  197. for (Iterator iter = methodGens.iterator(); iter.hasNext();) {
  198. LazyMethodGen gen = (LazyMethodGen) iter.next();
  199. // we skip empty clinits
  200. if (isEmptyClinit(gen)) continue;
  201. gen.print(out);
  202. if (iter.hasNext()) out.println();
  203. }
  204. // out.println(" ATTRIBS: " + Arrays.asList(myGen.getAttributes()));
  205. out.println("end " + toShortString());
  206. }
  207. private boolean isEmptyClinit(LazyMethodGen gen) {
  208. if (!gen.getName().equals("<clinit>")) return false;
  209. //System.err.println("checking clinig: " + gen);
  210. InstructionHandle start = gen.getBody().getStart();
  211. while (start != null) {
  212. if (Range.isRangeHandle(start) || (start.getInstruction() instanceof RETURN)) {
  213. start = start.getNext();
  214. } else {
  215. return false;
  216. }
  217. }
  218. return true;
  219. }
  220. public ConstantPoolGen getConstantPoolGen() {
  221. return constantPoolGen;
  222. }
  223. public String getName() {
  224. return myGen.getClassName();
  225. }
  226. public WeaverStateKind getWeaverState() {
  227. WeaverStateKind kind = myType.getWeaverState();
  228. if (kind == null) return WeaverStateKind.Untouched;
  229. return kind;
  230. }
  231. public void setWeaverState(WeaverStateKind s) {
  232. Attribute[] attributes = myGen.getAttributes();
  233. if (attributes != null) {
  234. for (int i = attributes.length - 1; i >=0; i--) {
  235. Attribute a = attributes[i];
  236. if (a instanceof Unknown) {
  237. Unknown u = (Unknown) a;
  238. if (u.getName().equals(AjAttribute.WeaverState.AttributeName)) {
  239. myGen.removeAttribute(u);
  240. }
  241. }
  242. }
  243. }
  244. myGen.addAttribute(BcelAttributes.bcelAttribute(
  245. new AjAttribute.WeaverState(s),
  246. getConstantPoolGen()));
  247. }
  248. public InstructionFactory getFactory() {
  249. return fact;
  250. }
  251. public LazyMethodGen getStaticInitializer() {
  252. for (Iterator i = methodGens.iterator(); i.hasNext();) {
  253. LazyMethodGen gen = (LazyMethodGen) i.next();
  254. if (gen.getName().equals("<clinit>")) return gen;
  255. }
  256. LazyMethodGen clinit = new LazyMethodGen(
  257. Modifier.STATIC,
  258. Type.VOID,
  259. "<clinit>",
  260. new Type[0],
  261. CollectionUtil.NO_STRINGS,
  262. this);
  263. clinit.getBody().insert(getFactory().RETURN);
  264. methodGens.add(clinit);
  265. return clinit;
  266. }
  267. public LazyMethodGen getAjcClinit() {
  268. for (Iterator i = methodGens.iterator(); i.hasNext();) {
  269. LazyMethodGen gen = (LazyMethodGen) i.next();
  270. if (gen.getName().equals(NameMangler.AJC_CLINIT_NAME)) return gen;
  271. }
  272. throw new RuntimeException("unimplemented");
  273. // LazyMethodGen clinit = new LazyMethodGen(
  274. // Modifier.STATIC,
  275. // Type.VOID,
  276. // "<clinit>",
  277. // new Type[0],
  278. // CollectionUtil.NO_STRINGS,
  279. // this);
  280. // clinit.getBody().insert(getFactory().RETURN);
  281. // methodGens.add(clinit);
  282. // return clinit;
  283. }
  284. // reflective thisJoinPoint support
  285. Map/*BcelShadow, Field*/ tjpFields = new HashMap();
  286. public static final ObjectType tjpType =
  287. new ObjectType("org.aspectj.lang.JoinPoint");
  288. public static final ObjectType staticTjpType =
  289. new ObjectType("org.aspectj.lang.JoinPoint$StaticPart");
  290. private static final ObjectType sigType =
  291. new ObjectType("org.aspectj.lang.Signature");
  292. private static final ObjectType slType =
  293. new ObjectType("org.aspectj.lang.reflect.SourceLocation");
  294. private static final ObjectType factoryType =
  295. new ObjectType("org.aspectj.runtime.reflect.Factory");
  296. private static final ObjectType classType =
  297. new ObjectType("java.lang.Class");
  298. public Field getTjpField(BcelShadow shadow) {
  299. Field ret = (Field)tjpFields.get(shadow);
  300. if (ret != null) return ret;
  301. ret = new FieldGen(Modifier.STATIC | Modifier.PUBLIC | Modifier.FINAL,
  302. staticTjpType,
  303. "ajc$tjp_" + tjpFields.size(),
  304. getConstantPoolGen()).getField();
  305. addField(ret);
  306. tjpFields.put(shadow, ret);
  307. return ret;
  308. }
  309. private void addAjcInitializers() {
  310. if (tjpFields.size() == 0) return;
  311. InstructionList il = initializeAllTjps();
  312. getStaticInitializer().getBody().insert(il);
  313. }
  314. private InstructionList initializeAllTjps() {
  315. InstructionList list = new InstructionList();
  316. InstructionFactory fact = getFactory();
  317. // make a new factory
  318. list.append(fact.createNew(factoryType));
  319. list.append(fact.createDup(1));
  320. list.append(new PUSH(getConstantPoolGen(), getFileName()));
  321. // load the current Class object
  322. //XXX check that this works correctly for inners/anonymous
  323. list.append(new PUSH(getConstantPoolGen(), getClassName()));
  324. //XXX do we need to worry about the fact the theorectically this could throw
  325. //a ClassNotFoundException
  326. list.append(fact.createInvoke("java.lang.Class", "forName", classType,
  327. new Type[] {Type.STRING}, Constants.INVOKESTATIC));
  328. list.append(fact.createInvoke(factoryType.getClassName(), "<init>",
  329. Type.VOID, new Type[] {Type.STRING, classType},
  330. Constants.INVOKESPECIAL));
  331. list.append(fact.createStore(factoryType, 0));
  332. List entries = new ArrayList(tjpFields.entrySet());
  333. Collections.sort(entries, new Comparator() {
  334. public int compare(Object a, Object b) {
  335. Map.Entry ae = (Map.Entry) a;
  336. Map.Entry be = (Map.Entry) b;
  337. return ((Field) ae.getValue())
  338. .getName()
  339. .compareTo(((Field)be.getValue()).getName());
  340. }
  341. });
  342. for (Iterator i = entries.iterator(); i.hasNext(); ) {
  343. Map.Entry entry = (Map.Entry)i.next();
  344. initializeTjp(fact, list, (Field)entry.getValue(), (BcelShadow)entry.getKey());
  345. }
  346. return list;
  347. }
  348. private void initializeTjp(InstructionFactory fact, InstructionList list,
  349. Field field, BcelShadow shadow)
  350. {
  351. Member sig = shadow.getSignature();
  352. //ResolvedMember mem = shadow.getSignature().resolve(shadow.getWorld());
  353. // load the factory
  354. list.append(fact.createLoad(factoryType, 0));
  355. // load the kind
  356. list.append(new PUSH(getConstantPoolGen(), shadow.getKind().getName()));
  357. // create the signature
  358. list.append(fact.createLoad(factoryType, 0));
  359. list.append(new PUSH(getConstantPoolGen(), sig.getSignatureString(shadow.getWorld())));
  360. list.append(fact.createInvoke(factoryType.getClassName(),
  361. sig.getSignatureMakerName(),
  362. new ObjectType(sig.getSignatureType()),
  363. new Type[] { Type.STRING },
  364. Constants.INVOKEVIRTUAL));
  365. //XXX should load source location from shadow
  366. list.append(Utility.createConstant(fact, shadow.getSourceLine()));
  367. list.append(fact.createInvoke(factoryType.getClassName(),
  368. "makeSJP", staticTjpType,
  369. new Type[] { Type.STRING, sigType, Type.INT},
  370. Constants.INVOKEVIRTUAL));
  371. // put it in the field
  372. list.append(fact.createFieldAccess(getClassName(), field.getName(),
  373. staticTjpType, Constants.PUTSTATIC));
  374. }
  375. public BcelObjectType getType() {
  376. return myType;
  377. }
  378. public String getFileName() {
  379. return myGen.getFileName();
  380. }
  381. public void addField(Field field) {
  382. myGen.addField(field);
  383. }
  384. public String getClassName() {
  385. return myGen.getClassName();
  386. }
  387. public boolean isInterface() {
  388. return myGen.isInterface();
  389. }
  390. public LazyMethodGen getLazyMethodGen(Member m) {
  391. return getLazyMethodGen(m.getName(), m.getSignature());
  392. }
  393. public LazyMethodGen getLazyMethodGen(String name, String signature) {
  394. for (Iterator i = methodGens.iterator(); i.hasNext();) {
  395. LazyMethodGen gen = (LazyMethodGen) i.next();
  396. if (gen.getName().equals(name) && gen.getSignature().equals(signature))
  397. return gen;
  398. }
  399. throw new BCException("Class " + this.getName() + " does not have a method "
  400. + name + " with signature " + signature);
  401. }
  402. public void forcePublic() {
  403. myGen.setAccessFlags(Utility.makePublic(myGen.getAccessFlags()));
  404. }
  405. }