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 51KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Contributors
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * Andy Clement 6Jul05 generics - signature attribute
  12. * ******************************************************************/
  13. package org.aspectj.weaver.bcel;
  14. import java.io.ByteArrayOutputStream;
  15. import java.io.File;
  16. import java.io.IOException;
  17. import java.io.PrintStream;
  18. import java.lang.reflect.Modifier;
  19. import java.util.ArrayList;
  20. import java.util.Collections;
  21. import java.util.Comparator;
  22. import java.util.HashMap;
  23. import java.util.Iterator;
  24. import java.util.List;
  25. import java.util.Map;
  26. import java.util.Set;
  27. import java.util.SortedMap;
  28. import java.util.TreeMap;
  29. import org.aspectj.apache.bcel.Constants;
  30. import org.aspectj.apache.bcel.classfile.Attribute;
  31. import org.aspectj.apache.bcel.classfile.ConstantUtf8;
  32. import org.aspectj.apache.bcel.classfile.Field;
  33. import org.aspectj.apache.bcel.classfile.JavaClass;
  34. import org.aspectj.apache.bcel.classfile.Method;
  35. import org.aspectj.apache.bcel.classfile.Signature;
  36. import org.aspectj.apache.bcel.classfile.Synthetic;
  37. import org.aspectj.apache.bcel.classfile.Unknown;
  38. import org.aspectj.apache.bcel.generic.BasicType;
  39. import org.aspectj.apache.bcel.generic.ClassGen;
  40. import org.aspectj.apache.bcel.classfile.ConstantPool;
  41. import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
  42. import org.aspectj.apache.bcel.generic.FieldGen;
  43. import org.aspectj.apache.bcel.generic.InstructionConstants;
  44. import org.aspectj.apache.bcel.generic.InstructionFactory;
  45. import org.aspectj.apache.bcel.generic.InstructionHandle;
  46. import org.aspectj.apache.bcel.generic.InstructionList;
  47. import org.aspectj.apache.bcel.generic.ObjectType;
  48. import org.aspectj.apache.bcel.generic.Type;
  49. import org.aspectj.bridge.IMessage;
  50. import org.aspectj.bridge.ISourceLocation;
  51. import org.aspectj.bridge.SourceLocation;
  52. import org.aspectj.util.LangUtil;
  53. import org.aspectj.weaver.AjAttribute;
  54. import org.aspectj.weaver.BCException;
  55. import org.aspectj.weaver.Member;
  56. import org.aspectj.weaver.NameMangler;
  57. import org.aspectj.weaver.ResolvedMember;
  58. import org.aspectj.weaver.ResolvedType;
  59. import org.aspectj.weaver.Shadow;
  60. import org.aspectj.weaver.TypeVariable;
  61. import org.aspectj.weaver.UnresolvedType;
  62. import org.aspectj.weaver.WeaverMessages;
  63. import org.aspectj.weaver.WeaverStateInfo;
  64. import org.aspectj.weaver.World;
  65. import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
  66. /**
  67. * Lazy lazy lazy.
  68. * We don't unpack the underlying class unless necessary. Things
  69. * like new methods and annotations accumulate in here until they
  70. * must be written out, don't add them to the underlying MethodGen!
  71. * Things are slightly different if this represents an Aspect.
  72. */
  73. public final class LazyClassGen {
  74. private static final int ACC_SYNTHETIC = 0x1000;
  75. int highestLineNumber = 0; // ---- JSR 45 info
  76. private SortedMap /* <String, InlinedSourceFileInfo> */ inlinedFiles = new TreeMap();
  77. private boolean regenerateGenericSignatureAttribute = false;
  78. private BcelObjectType myType; // XXX is not set for types we create
  79. private ClassGen myGen;
  80. private ConstantPool constantPoolGen;
  81. private World world;
  82. private String packageName = null;
  83. private List /*BcelField*/ fields = new ArrayList();
  84. private List /*LazyMethodGen*/ methodGens = new ArrayList();
  85. private List /*LazyClassGen*/ classGens = new ArrayList();
  86. private List /*AnnotationGen*/ annotations = new ArrayList();
  87. private int childCounter = 0;
  88. private InstructionFactory fact;
  89. private boolean isSerializable = false;
  90. private boolean hasSerialVersionUIDField = false;
  91. private boolean serialVersionUIDRequiresInitialization = false;
  92. private long calculatedSerialVersionUID;
  93. private boolean hasClinit = false;
  94. // ---
  95. static class InlinedSourceFileInfo {
  96. int highestLineNumber;
  97. int offset; // calculated
  98. InlinedSourceFileInfo(int highestLineNumber) {
  99. this.highestLineNumber = highestLineNumber;
  100. }
  101. }
  102. void addInlinedSourceFileInfo(String fullpath, int highestLineNumber) {
  103. Object o = inlinedFiles.get(fullpath);
  104. if (o != null) {
  105. InlinedSourceFileInfo info = (InlinedSourceFileInfo) o;
  106. if (info.highestLineNumber < highestLineNumber) {
  107. info.highestLineNumber = highestLineNumber;
  108. }
  109. } else {
  110. inlinedFiles.put(fullpath, new InlinedSourceFileInfo(highestLineNumber));
  111. }
  112. }
  113. void calculateSourceDebugExtensionOffsets() {
  114. int i = roundUpToHundreds(highestLineNumber);
  115. for (Iterator iter = inlinedFiles.values().iterator(); iter.hasNext();) {
  116. InlinedSourceFileInfo element = (InlinedSourceFileInfo) iter.next();
  117. element.offset = i;
  118. i = roundUpToHundreds(i + element.highestLineNumber);
  119. }
  120. }
  121. private static int roundUpToHundreds(int i) {
  122. return ((i / 100) + 1) * 100;
  123. }
  124. int getSourceDebugExtensionOffset(String fullpath) {
  125. return ((InlinedSourceFileInfo) inlinedFiles.get(fullpath)).offset;
  126. }
  127. private Unknown getSourceDebugExtensionAttribute() {
  128. int nameIndex = constantPoolGen.addUtf8("SourceDebugExtension");
  129. String data = getSourceDebugExtensionString();
  130. //System.err.println(data);
  131. byte[] bytes = Utility.stringToUTF(data);
  132. int length = bytes.length;
  133. return new Unknown(nameIndex, length, bytes, constantPoolGen);
  134. }
  135. // private LazyClassGen() {}
  136. // public static void main(String[] args) {
  137. // LazyClassGen m = new LazyClassGen();
  138. // m.highestLineNumber = 37;
  139. // m.inlinedFiles.put("boo/baz/foo.java", new InlinedSourceFileInfo( 83));
  140. // m.inlinedFiles.put("boo/barz/foo.java", new InlinedSourceFileInfo(292));
  141. // m.inlinedFiles.put("boo/baz/moo.java", new InlinedSourceFileInfo(128));
  142. // m.calculateSourceDebugExtensionOffsets();
  143. // System.err.println(m.getSourceDebugExtensionString());
  144. // }
  145. // For the entire pathname, we're using package names. This is probably wrong.
  146. private String getSourceDebugExtensionString() {
  147. StringBuffer out = new StringBuffer();
  148. String myFileName = getFileName();
  149. // header section
  150. out.append("SMAP\n");
  151. out.append(myFileName);
  152. out.append("\nAspectJ\n");
  153. // stratum section
  154. out.append("*S AspectJ\n");
  155. // file section
  156. out.append("*F\n");
  157. out.append("1 ");
  158. out.append(myFileName);
  159. out.append("\n");
  160. int i = 2;
  161. for (Iterator iter = inlinedFiles.keySet().iterator(); iter.hasNext();) {
  162. String element = (String) iter.next();
  163. int ii = element.lastIndexOf('/');
  164. if (ii == -1) {
  165. out.append(i++); out.append(' ');
  166. out.append(element); out.append('\n');
  167. } else {
  168. out.append("+ "); out.append(i++); out.append(' ');
  169. out.append(element.substring(ii+1)); out.append('\n');
  170. out.append(element); out.append('\n');
  171. }
  172. }
  173. // emit line section
  174. out.append("*L\n");
  175. out.append("1#1,");
  176. out.append(highestLineNumber);
  177. out.append(":1,1\n");
  178. i = 2;
  179. for (Iterator iter = inlinedFiles.values().iterator(); iter.hasNext();) {
  180. InlinedSourceFileInfo element = (InlinedSourceFileInfo) iter.next();
  181. out.append("1#");
  182. out.append(i++); out.append(',');
  183. out.append(element.highestLineNumber); out.append(":");
  184. out.append(element.offset + 1); out.append(",1\n");
  185. }
  186. // end section
  187. out.append("*E\n");
  188. // and finish up...
  189. return out.toString();
  190. }
  191. // ---- end JSR45-related stuff
  192. /** Emit disassembled class and newline to out */
  193. public static void disassemble(String path, String name, PrintStream out)
  194. throws IOException {
  195. if (null == out) {
  196. return;
  197. }
  198. //out.println("classPath: " + classPath);
  199. BcelWorld world = new BcelWorld(path);
  200. UnresolvedType ut = UnresolvedType.forName(name);
  201. ut.setNeedsModifiableDelegate(true);
  202. LazyClassGen clazz = new LazyClassGen(BcelWorld.getBcelObjectType(world.resolve(ut)));
  203. clazz.print(out);
  204. out.println();
  205. }
  206. public int getNewGeneratedNameTag() {
  207. return childCounter++;
  208. }
  209. // ----
  210. public LazyClassGen(
  211. String class_name,
  212. String super_class_name,
  213. String file_name,
  214. int access_flags,
  215. String[] interfaces,
  216. World world)
  217. {
  218. myGen = new ClassGen(class_name, super_class_name, file_name, access_flags, interfaces);
  219. constantPoolGen = myGen.getConstantPool();
  220. fact = new InstructionFactory(myGen, constantPoolGen);
  221. regenerateGenericSignatureAttribute = true;
  222. this.world = world;
  223. }
  224. //Non child type, so it comes from a real type in the world.
  225. public LazyClassGen(BcelObjectType myType) {
  226. myGen = new ClassGen(myType.getJavaClass());
  227. constantPoolGen = myGen.getConstantPool();
  228. fact = new InstructionFactory(myGen, constantPoolGen);
  229. this.myType = myType;
  230. this.world = myType.getResolvedTypeX().getWorld();
  231. /* Does this class support serialization */
  232. if (implementsSerializable(getType())) {
  233. isSerializable = true;
  234. // ResolvedMember[] fields = getType().getDeclaredFields();
  235. // for (int i = 0; i < fields.length; i++) {
  236. // ResolvedMember field = fields[i];
  237. // if (field.getName().equals("serialVersionUID")
  238. // && field.isStatic() && field.getType().equals(ResolvedType.LONG)) {
  239. // hasSerialVersionUIDField = true;
  240. // }
  241. // }
  242. hasSerialVersionUIDField = hasSerialVersionUIDField(getType());
  243. ResolvedMember[] methods = getType().getDeclaredMethods();
  244. for (int i = 0; i < methods.length; i++) {
  245. ResolvedMember method = methods[i];
  246. if (method.getName().equals("<clinit>")) {
  247. hasClinit = true;
  248. }
  249. }
  250. // Do we need to calculate an SUID and add it?
  251. if (!hasSerialVersionUIDField && world.isAddSerialVerUID()) {
  252. calculatedSerialVersionUID = myGen.getSUID();
  253. FieldGen fg = new FieldGen(
  254. Constants.ACC_PRIVATE|Constants.ACC_FINAL|Constants.ACC_STATIC,
  255. BasicType.LONG,"serialVersionUID",getConstantPool());
  256. addField(fg);
  257. hasSerialVersionUIDField=true;
  258. serialVersionUIDRequiresInitialization=true;
  259. // warn about what we've done?
  260. if (world.getLint().calculatingSerialVersionUID.isEnabled())
  261. world.getLint().calculatingSerialVersionUID.signal(
  262. new String[]{getClassName(),Long.toString(calculatedSerialVersionUID)+"L"},null,null);
  263. }
  264. }
  265. ResolvedMember[] methods = myType.getDeclaredMethods();
  266. for (int i=0; i<methods.length; i++) {
  267. addMethodGen(new LazyMethodGen((BcelMethod)methods[i],this));
  268. }
  269. ResolvedMember[] fields = myType.getDeclaredFields();
  270. for (int i=0; i<fields.length; i++) {
  271. this.fields.add((BcelField)fields[i]);
  272. }
  273. }
  274. public static boolean hasSerialVersionUIDField (ResolvedType type) {
  275. ResolvedMember[] fields = type.getDeclaredFields();
  276. for (int i = 0; i < fields.length; i++) {
  277. ResolvedMember field = fields[i];
  278. if (field.getName().equals("serialVersionUID")
  279. && field.isStatic() && field.getType().equals(ResolvedType.LONG)) {
  280. return true;
  281. }
  282. }
  283. return false;
  284. }
  285. // public void addAttribute(Attribute i) {
  286. // myGen.addAttribute(i);
  287. // }
  288. // ----
  289. public String getInternalClassName() {
  290. return getConstantPool().getConstantString_CONSTANTClass(myGen.getClassNameIndex());
  291. //getConstantPool().getConstantString(
  292. // myGen.getClassNameIndex(),
  293. // Constants.CONSTANT_Class);
  294. }
  295. public String getInternalFileName() {
  296. String str = getInternalClassName();
  297. int index = str.lastIndexOf('/');
  298. if (index == -1) {
  299. return getFileName();
  300. } else {
  301. return str.substring(0, index + 1) + getFileName();
  302. }
  303. }
  304. public File getPackagePath(File root) {
  305. String str = getInternalClassName();
  306. int index = str.lastIndexOf('/');
  307. if (index == -1)
  308. return root;
  309. return new File(root, str.substring(0, index));
  310. }
  311. /** Returns the packagename - if its the default package we return an empty string
  312. */
  313. public String getPackageName() {
  314. if (packageName!=null) return packageName;
  315. String str = getInternalClassName();
  316. int index = str.indexOf("<");
  317. if (index!=-1) str = str.substring(0,index); // strip off the generics guff
  318. index= str.lastIndexOf("/");
  319. if (index==-1) return "";
  320. return str.substring(0,index).replace('/','.');
  321. }
  322. public String getClassId() {
  323. String str = getInternalClassName();
  324. int index = str.lastIndexOf('/');
  325. if (index == -1)
  326. return str;
  327. return str.substring(index + 1);
  328. }
  329. public void addMethodGen(LazyMethodGen gen) {
  330. //assert gen.getClassName() == super.getClassName();
  331. methodGens.add(gen);
  332. if (highestLineNumber < gen.highestLineNumber) highestLineNumber = gen.highestLineNumber;
  333. }
  334. public void addMethodGen(LazyMethodGen gen, ISourceLocation sourceLocation) {
  335. addMethodGen(gen);
  336. if (!gen.getMethod().isPrivate()) {
  337. warnOnAddedMethod(gen.getMethod(),sourceLocation);
  338. }
  339. }
  340. public void errorOnAddedField (FieldGen field, ISourceLocation sourceLocation) {
  341. if (isSerializable && !hasSerialVersionUIDField) {
  342. getWorld().getLint().serialVersionUIDBroken.signal(
  343. new String[] {
  344. myType.getResolvedTypeX().getName().toString(),
  345. field.getName()
  346. },
  347. sourceLocation,
  348. null);
  349. }
  350. }
  351. public void warnOnAddedInterface (String name, ISourceLocation sourceLocation) {
  352. warnOnModifiedSerialVersionUID(sourceLocation,"added interface " + name);
  353. }
  354. public void warnOnAddedMethod (Method method, ISourceLocation sourceLocation) {
  355. warnOnModifiedSerialVersionUID(sourceLocation,"added non-private method " + method.getName());
  356. }
  357. public void warnOnAddedStaticInitializer (Shadow shadow, ISourceLocation sourceLocation) {
  358. if (!hasClinit) {
  359. warnOnModifiedSerialVersionUID(sourceLocation,"added static initializer");
  360. }
  361. }
  362. public void warnOnModifiedSerialVersionUID (ISourceLocation sourceLocation, String reason) {
  363. if (isSerializable && !hasSerialVersionUIDField)
  364. getWorld().getLint().needsSerialVersionUIDField.signal(
  365. new String[] {
  366. myType.getResolvedTypeX().getName().toString(),
  367. reason
  368. },
  369. sourceLocation,
  370. null);
  371. }
  372. public World getWorld () {
  373. return world;
  374. }
  375. public List getMethodGens() {
  376. return methodGens; //???Collections.unmodifiableList(methodGens);
  377. }
  378. public List/*BcelField*/ getFieldGens() {
  379. return fields;
  380. // return myGen.getFields();
  381. }
  382. // public Field getField(String name) {
  383. // Field[] allFields = myGen.getFields();
  384. // if (allFields==null) return null;
  385. // for (int i = 0; i < allFields.length; i++) {
  386. // Field field = allFields[i];
  387. // if (field.getName().equals(name)) return field;
  388. // }
  389. // return null;
  390. // }
  391. // FIXME asc How do the ones on the underlying class surface if this just returns new ones added?
  392. // FIXME asc ...although no one calls this right now !
  393. public List getAnnotations() {
  394. return annotations;
  395. }
  396. private void writeBack(BcelWorld world) {
  397. if (getConstantPool().getSize() > Short.MAX_VALUE) {
  398. reportClassTooBigProblem();
  399. return;
  400. }
  401. if (annotations.size()>0) {
  402. for (Iterator iter = annotations.iterator(); iter.hasNext();) {
  403. AnnotationGen element = (AnnotationGen) iter.next();
  404. myGen.addAnnotation(element);
  405. }
  406. // Attribute[] annAttributes = org.aspectj.apache.bcel.classfile.Utility.getAnnotationAttributes(getConstantPool(),annotations);
  407. // for (int i = 0; i < annAttributes.length; i++) {
  408. // Attribute attribute = annAttributes[i];
  409. // System.err.println("Adding attribute for "+attribute);
  410. // myGen.addAttribute(attribute);
  411. // }
  412. }
  413. // Add a weaver version attribute to the file being produced (if necessary...)
  414. if (!myGen.hasAttribute("org.aspectj.weaver.WeaverVersion")) {
  415. myGen.addAttribute(Utility.bcelAttribute(new AjAttribute.WeaverVersionInfo(),getConstantPool()));
  416. }
  417. if (myType != null && myType.getWeaverState() != null) {
  418. myGen.addAttribute(Utility.bcelAttribute(
  419. new AjAttribute.WeaverState(myType.getWeaverState()),
  420. getConstantPool()));
  421. }
  422. //FIXME ATAJ needed only for slow Aspects.aspectOf() - keep or remove
  423. //make a lot of test fail since the test compare weaved class file
  424. // based on some test data as text files...
  425. // if (!myGen.isInterface()) {
  426. // addAjClassField();
  427. // }
  428. addAjcInitializers();
  429. // 17Feb05 - ASC - Skip this for now - it crashes IBM 1.4.2 jvms (pr80430). Will be revisited when contents
  430. // of attribute are confirmed to be correct.
  431. boolean sourceDebugExtensionSupportSwitchedOn = false;
  432. if (sourceDebugExtensionSupportSwitchedOn) {
  433. calculateSourceDebugExtensionOffsets();
  434. }
  435. int len = methodGens.size();
  436. myGen.setMethods(Method.NoMethods);
  437. for (int i = 0; i < len; i++) {
  438. LazyMethodGen gen = (LazyMethodGen) methodGens.get(i);
  439. // we skip empty clinits
  440. if (isEmptyClinit(gen)) continue;
  441. myGen.addMethod(gen.getMethod());
  442. }
  443. len = fields.size();
  444. myGen.setFields(Field.NoFields);
  445. for (int i = 0; i < len; i++) {
  446. BcelField gen = (BcelField) fields.get(i);
  447. myGen.addField(gen.getField(this.constantPoolGen));
  448. }
  449. if (sourceDebugExtensionSupportSwitchedOn) {
  450. if (inlinedFiles.size() != 0) {
  451. if (hasSourceDebugExtensionAttribute(myGen)) {
  452. world.showMessage(
  453. IMessage.WARNING,
  454. WeaverMessages.format(WeaverMessages.OVERWRITE_JSR45,getFileName()),
  455. null,
  456. null);
  457. }
  458. // myGen.addAttribute(getSourceDebugExtensionAttribute());
  459. }
  460. }
  461. fixupGenericSignatureAttribute();
  462. }
  463. /**
  464. * When working with 1.5 generics, a signature attribute is attached to the type which indicates
  465. * how it was declared. This routine ensures the signature attribute for what we are about
  466. * to write out is correct. Basically its responsibilities are:
  467. * 1. Checking whether the attribute needs changing (i.e. did weaving change the type hierarchy)
  468. * 2. If it did, removing the old attribute
  469. * 3. Check if we need an attribute at all, are we generic? are our supertypes parameterized/generic?
  470. * 4. Build the new attribute which includes all typevariable, supertype and superinterface information
  471. */
  472. private void fixupGenericSignatureAttribute () {
  473. if (getWorld() != null && !getWorld().isInJava5Mode()) return;
  474. // TODO asc generics Temporarily assume that types we generate dont need a signature attribute (closure/etc).. will need revisiting no doubt...
  475. if (myType==null) return;
  476. // 1. Has anything changed that would require us to modify this attribute?
  477. if (!regenerateGenericSignatureAttribute) return;
  478. // 2. Find the old attribute
  479. Signature sigAttr = null;
  480. if (myType!=null) { // if null, this is a type built from scratch, it won't already have a sig attribute
  481. sigAttr = (Signature) myGen.getAttribute("Signature");
  482. }
  483. // 3. Do we need an attribute?
  484. boolean needAttribute = false;
  485. if (sigAttr!=null) needAttribute = true; // If we had one before, we definetly still need one as types can't be 'removed' from the hierarchy
  486. // check the interfaces
  487. if (!needAttribute) {
  488. if (myType==null) {
  489. boolean stop = true;
  490. }
  491. ResolvedType[] interfaceRTXs = myType.getDeclaredInterfaces();
  492. for (int i = 0; i < interfaceRTXs.length; i++) {
  493. ResolvedType typeX = interfaceRTXs[i];
  494. if (typeX.isGenericType() || typeX.isParameterizedType()) needAttribute = true;
  495. }
  496. // check the supertype
  497. ResolvedType superclassRTX = myType.getSuperclass();
  498. if (superclassRTX.isGenericType() || superclassRTX.isParameterizedType()) needAttribute = true;
  499. }
  500. if (needAttribute) {
  501. StringBuffer signature = new StringBuffer();
  502. // first, the type variables...
  503. TypeVariable[] tVars = myType.getTypeVariables();
  504. if (tVars.length>0) {
  505. signature.append("<");
  506. for (int i = 0; i < tVars.length; i++) {
  507. TypeVariable variable = tVars[i];
  508. signature.append(variable.getSignature());
  509. }
  510. signature.append(">");
  511. }
  512. // now the supertype
  513. String supersig = myType.getSuperclass().getSignatureForAttribute();
  514. signature.append(supersig);
  515. ResolvedType[] interfaceRTXs = myType.getDeclaredInterfaces();
  516. for (int i = 0; i < interfaceRTXs.length; i++) {
  517. String s = interfaceRTXs[i].getSignatureForAttribute();
  518. signature.append(s);
  519. }
  520. if (sigAttr!=null) myGen.removeAttribute(sigAttr);
  521. myGen.addAttribute(createSignatureAttribute(signature.toString()));
  522. }
  523. }
  524. /**
  525. * Helper method to create a signature attribute based on a string signature:
  526. * e.g. "Ljava/lang/Object;LI<Ljava/lang/Double;>;"
  527. */
  528. private Signature createSignatureAttribute(String signature) {
  529. int nameIndex = constantPoolGen.addUtf8("Signature");
  530. int sigIndex = constantPoolGen.addUtf8(signature);
  531. return new Signature(nameIndex,2,sigIndex,constantPoolGen);
  532. }
  533. /**
  534. *
  535. */
  536. private void reportClassTooBigProblem() {
  537. // PR 59208
  538. // we've generated a class that is just toooooooooo big (you've been generating programs
  539. // again haven't you? come on, admit it, no-one writes classes this big by hand).
  540. // create an empty myGen so that we can give back a return value that doesn't upset the
  541. // rest of the process.
  542. myGen = new ClassGen(myGen.getClassName(), myGen.getSuperclassName(),
  543. myGen.getFileName(), myGen.getModifiers(), myGen.getInterfaceNames());
  544. // raise an error against this compilation unit.
  545. getWorld().showMessage(
  546. IMessage.ERROR,
  547. WeaverMessages.format(WeaverMessages.CLASS_TOO_BIG,
  548. this.getClassName()),
  549. new SourceLocation(new File(myGen.getFileName()),0), null
  550. );
  551. }
  552. private static boolean hasSourceDebugExtensionAttribute(ClassGen gen) {
  553. return gen.hasAttribute("SourceDebugExtension");
  554. // ConstantPool pool = gen.getConstantPool();
  555. // Attribute[] attrs = gen.getAttributes();
  556. // for (int i = 0; i < attrs.length; i++) {
  557. // if ("SourceDebugExtension"
  558. // .equals(((ConstantUtf8) pool.getConstant(attrs[i].getNameIndex())).getBytes())) {
  559. // return true;
  560. // }
  561. // }
  562. // return false;
  563. }
  564. public JavaClass getJavaClass(BcelWorld world) {
  565. writeBack(world);
  566. return myGen.getJavaClass();
  567. }
  568. public byte [] getJavaClassBytesIncludingReweavable(BcelWorld world){
  569. writeBack(world);
  570. byte [] wovenClassFileData = myGen.getJavaClass().getBytes();
  571. WeaverStateInfo wsi = myType.getWeaverState();//getOrCreateWeaverStateInfo();
  572. if(wsi != null && wsi.isReweavable()){ // && !reweavableDataInserted
  573. //reweavableDataInserted = true;
  574. return wsi.replaceKeyWithDiff(wovenClassFileData);
  575. } else{
  576. return wovenClassFileData;
  577. }
  578. }
  579. public void addGeneratedInner(LazyClassGen newClass) {
  580. classGens.add(newClass);
  581. }
  582. public void addInterface(UnresolvedType typeX, ISourceLocation sourceLocation) {
  583. regenerateGenericSignatureAttribute = true;
  584. myGen.addInterface(typeX.getRawName());
  585. if (!typeX.equals(UnresolvedType.SERIALIZABLE))
  586. warnOnAddedInterface(typeX.getName(),sourceLocation);
  587. }
  588. public void setSuperClass(ResolvedType typeX) {
  589. regenerateGenericSignatureAttribute = true;
  590. myType.addParent(typeX); // used for the attribute
  591. if (typeX.getGenericType()!=null) typeX = typeX.getGenericType();
  592. myGen.setSuperclassName(typeX.getName()); // used in the real class data
  593. }
  594. public String getSuperClassname() {
  595. return myGen.getSuperclassName();
  596. }
  597. // FIXME asc not great that some of these ask the gen and some ask the type ! (see the related setters too)
  598. public ResolvedType getSuperClass() {
  599. return myType.getSuperclass();
  600. }
  601. public String[] getInterfaceNames() {
  602. return myGen.getInterfaceNames();
  603. }
  604. // non-recursive, may be a bug, ha ha.
  605. private List getClassGens() {
  606. List ret = new ArrayList();
  607. ret.add(this);
  608. ret.addAll(classGens);
  609. return ret;
  610. }
  611. public List getChildClasses(BcelWorld world) {
  612. if (classGens.isEmpty()) return Collections.EMPTY_LIST;
  613. List ret = new ArrayList();
  614. for (Iterator i = classGens.iterator(); i.hasNext();) {
  615. LazyClassGen clazz = (LazyClassGen) i.next();
  616. byte[] bytes = clazz.getJavaClass(world).getBytes();
  617. String name = clazz.getName();
  618. int index = name.lastIndexOf('$');
  619. // XXX this could be bad, check use of dollar signs.
  620. name = name.substring(index+1);
  621. ret.add(new UnwovenClassFile.ChildClass(name, bytes));
  622. }
  623. return ret;
  624. }
  625. public String toString() {
  626. return toShortString();
  627. }
  628. public String toShortString() {
  629. String s =
  630. org.aspectj.apache.bcel.classfile.Utility.accessToString(myGen.getModifiers(), true);
  631. if (s != "")
  632. s += " ";
  633. s += org.aspectj.apache.bcel.classfile.Utility.classOrInterface(myGen.getModifiers());
  634. s += " ";
  635. s += myGen.getClassName();
  636. return s;
  637. }
  638. public String toLongString() {
  639. ByteArrayOutputStream s = new ByteArrayOutputStream();
  640. print(new PrintStream(s));
  641. return new String(s.toByteArray());
  642. }
  643. public void print() { print(System.out); }
  644. public void print(PrintStream out) {
  645. List classGens = getClassGens();
  646. for (Iterator iter = classGens.iterator(); iter.hasNext();) {
  647. LazyClassGen element = (LazyClassGen) iter.next();
  648. element.printOne(out);
  649. if (iter.hasNext()) out.println();
  650. }
  651. }
  652. private void printOne(PrintStream out) {
  653. out.print(toShortString());
  654. out.print(" extends ");
  655. out.print(
  656. org.aspectj.apache.bcel.classfile.Utility.compactClassName(
  657. myGen.getSuperclassName(),
  658. false));
  659. int size = myGen.getInterfaces().length;
  660. if (size > 0) {
  661. out.print(" implements ");
  662. for (int i = 0; i < size; i++) {
  663. out.print(myGen.getInterfaceNames()[i]);
  664. if (i < size - 1)
  665. out.print(", ");
  666. }
  667. }
  668. out.print(":");
  669. out.println();
  670. // XXX make sure to pass types correctly around, so this doesn't happen.
  671. if (myType != null) {
  672. myType.printWackyStuff(out);
  673. }
  674. Field[] fields = myGen.getFields();
  675. for (int i = 0, len = fields.length; i < len; i++) {
  676. out.print(" ");
  677. out.println(fields[i]);
  678. }
  679. List methodGens = getMethodGens();
  680. for (Iterator iter = methodGens.iterator(); iter.hasNext();) {
  681. LazyMethodGen gen = (LazyMethodGen) iter.next();
  682. // we skip empty clinits
  683. if (isEmptyClinit(gen)) continue;
  684. gen.print(out, (myType != null ? myType.getWeaverVersionAttribute() : WeaverVersionInfo.UNKNOWN));
  685. if (iter.hasNext()) out.println();
  686. }
  687. // out.println(" ATTRIBS: " + Arrays.asList(myGen.getAttributes()));
  688. out.println("end " + toShortString());
  689. }
  690. private boolean isEmptyClinit(LazyMethodGen gen) {
  691. if (!gen.getName().equals("<clinit>")) return false;
  692. //System.err.println("checking clinig: " + gen);
  693. InstructionHandle start = gen.getBody().getStart();
  694. while (start != null) {
  695. if (Range.isRangeHandle(start) || (start.getInstruction().opcode==Constants.RETURN)) {
  696. start = start.getNext();
  697. } else {
  698. return false;
  699. }
  700. }
  701. return true;
  702. }
  703. public ConstantPool getConstantPool() {
  704. return constantPoolGen;
  705. }
  706. public String getName() {
  707. return myGen.getClassName();
  708. }
  709. public boolean isWoven() {
  710. return myType.getWeaverState() != null;
  711. }
  712. public boolean isReweavable() {
  713. if (myType.getWeaverState()==null) return true;
  714. return myType.getWeaverState().isReweavable();
  715. }
  716. public Set getAspectsAffectingType() {
  717. if (myType.getWeaverState()==null) return null;
  718. return myType.getWeaverState().getAspectsAffectingType();
  719. }
  720. public WeaverStateInfo getOrCreateWeaverStateInfo(boolean inReweavableMode) {
  721. WeaverStateInfo ret = myType.getWeaverState();
  722. if (ret != null) return ret;
  723. ret = new WeaverStateInfo(inReweavableMode);
  724. myType.setWeaverState(ret);
  725. return ret;
  726. }
  727. public InstructionFactory getFactory() {
  728. return fact;
  729. }
  730. public LazyMethodGen getStaticInitializer() {
  731. for (Iterator i = methodGens.iterator(); i.hasNext();) {
  732. LazyMethodGen gen = (LazyMethodGen) i.next();
  733. if (gen.getName().equals("<clinit>")) return gen;
  734. }
  735. LazyMethodGen clinit = new LazyMethodGen(
  736. Modifier.STATIC,
  737. Type.VOID,
  738. "<clinit>",
  739. new Type[0],
  740. LangUtil.NO_STRINGS,
  741. this);
  742. clinit.getBody().insert(InstructionConstants.RETURN);
  743. methodGens.add(clinit);
  744. return clinit;
  745. }
  746. public LazyMethodGen getAjcPreClinit() {
  747. for (Iterator i = methodGens.iterator(); i.hasNext();) {
  748. LazyMethodGen gen = (LazyMethodGen) i.next();
  749. if (gen.getName().equals(NameMangler.AJC_PRE_CLINIT_NAME)) return gen;
  750. }
  751. LazyMethodGen ajcClinit = new LazyMethodGen(
  752. Modifier.STATIC,
  753. Type.VOID,
  754. NameMangler.AJC_PRE_CLINIT_NAME,
  755. new Type[0],
  756. LangUtil.NO_STRINGS,
  757. this);
  758. ajcClinit.getBody().insert(InstructionConstants.RETURN);
  759. methodGens.add(ajcClinit);
  760. getStaticInitializer().getBody().insert(Utility.createInvoke(getFactory(), ajcClinit));
  761. return ajcClinit;
  762. }
  763. // reflective thisJoinPoint support
  764. Map/*BcelShadow, Field*/ tjpFields = new HashMap();
  765. public static final ObjectType proceedingTjpType =
  766. new ObjectType("org.aspectj.lang.ProceedingJoinPoint");
  767. public static final ObjectType tjpType =
  768. new ObjectType("org.aspectj.lang.JoinPoint");
  769. public static final ObjectType staticTjpType =
  770. new ObjectType("org.aspectj.lang.JoinPoint$StaticPart");
  771. public static final ObjectType enclosingStaticTjpType =
  772. new ObjectType("org.aspectj.lang.JoinPoint$EnclosingStaticPart");
  773. private static final ObjectType sigType =
  774. new ObjectType("org.aspectj.lang.Signature");
  775. // private static final ObjectType slType =
  776. // new ObjectType("org.aspectj.lang.reflect.SourceLocation");
  777. private static final ObjectType factoryType =
  778. new ObjectType("org.aspectj.runtime.reflect.Factory");
  779. private static final ObjectType classType =
  780. new ObjectType("java.lang.Class");
  781. public Field getTjpField(BcelShadow shadow, final boolean isEnclosingJp) {
  782. Field ret = (Field)tjpFields.get(shadow);
  783. if (ret != null) return ret;
  784. int modifiers = Modifier.STATIC | Modifier.FINAL;
  785. // XXX - Do we ever inline before or after advice? If we do, then we
  786. // better include them in the check below. (or just change it to
  787. // shadow.getEnclosingMethod().getCanInline())
  788. // If the enclosing method is around advice, we could inline the join point
  789. // that has led to this shadow. If we do that then the TJP we are creating
  790. // here must be PUBLIC so it is visible to the type in which the
  791. // advice is inlined. (PR71377)
  792. LazyMethodGen encMethod = shadow.getEnclosingMethod();
  793. boolean shadowIsInAroundAdvice = false;
  794. if (encMethod!=null && encMethod.getName().startsWith(NameMangler.PREFIX+"around")) {
  795. shadowIsInAroundAdvice = true;
  796. }
  797. if (getType().isInterface() || shadowIsInAroundAdvice) {
  798. modifiers |= Modifier.PUBLIC;
  799. }
  800. else {
  801. modifiers |= Modifier.PRIVATE;
  802. }
  803. ObjectType jpType = null;
  804. if (world.isTargettingAspectJRuntime12()) { // TAG:SUPPORTING12: We didn't have different staticjp types in 1.2
  805. jpType = staticTjpType;
  806. } else {
  807. jpType = isEnclosingJp?enclosingStaticTjpType:staticTjpType;
  808. }
  809. FieldGen fGen = new FieldGen(modifiers,jpType,"ajc$tjp_" + tjpFields.size(),getConstantPool());
  810. addField(fGen);
  811. ret = fGen.getField();
  812. tjpFields.put(shadow, ret);
  813. return ret;
  814. }
  815. //FIXME ATAJ needed only for slow Aspects.aspectOf - keep or remove
  816. // private void addAjClassField() {
  817. // // Andy: Why build it again??
  818. // Field ajClassField = new FieldGen(
  819. // Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC,
  820. // classType,
  821. // "aj$class",
  822. // getConstantPool()).getField();
  823. // addField(ajClassField);
  824. //
  825. // InstructionList il = new InstructionList();
  826. // il.append(new PUSH(getConstantPool(), getClassName()));
  827. // il.append(fact.createInvoke("java.lang.Class", "forName", classType,
  828. // new Type[] {Type.STRING}, Constants.INVOKESTATIC));
  829. // il.append(fact.createFieldAccess(getClassName(), ajClassField.getName(),
  830. // classType, Constants.PUTSTATIC));
  831. //
  832. // getStaticInitializer().getBody().insert(il);
  833. // }
  834. private void addAjcInitializers() {
  835. if (tjpFields.size() == 0 && !serialVersionUIDRequiresInitialization) return;
  836. InstructionList il = null;
  837. if (tjpFields.size()>0) {
  838. il = initializeAllTjps();
  839. }
  840. if (serialVersionUIDRequiresInitialization) {
  841. if (il==null) {
  842. il= new InstructionList();
  843. }
  844. il.append(InstructionFactory.PUSH(getConstantPool(),calculatedSerialVersionUID));
  845. il.append(getFactory().createFieldAccess(getClassName(), "serialVersionUID", BasicType.LONG, Constants.PUTSTATIC));
  846. }
  847. getStaticInitializer().getBody().insert(il);
  848. }
  849. private InstructionList initializeAllTjps() {
  850. InstructionList list = new InstructionList();
  851. InstructionFactory fact = getFactory();
  852. // make a new factory
  853. list.append(fact.createNew(factoryType));
  854. list.append(InstructionFactory.createDup(1));
  855. list.append(InstructionFactory.PUSH(getConstantPool(), getFileName()));
  856. // load the current Class object
  857. //XXX check that this works correctly for inners/anonymous
  858. list.append(InstructionFactory.PUSH(getConstantPool(), getClassName()));
  859. //XXX do we need to worry about the fact the theorectically this could throw
  860. //a ClassNotFoundException
  861. list.append(fact.createInvoke("java.lang.Class", "forName", classType,
  862. new Type[] {Type.STRING}, Constants.INVOKESTATIC));
  863. list.append(fact.createInvoke(factoryType.getClassName(), "<init>",
  864. Type.VOID, new Type[] {Type.STRING, classType},
  865. Constants.INVOKESPECIAL));
  866. list.append(InstructionFactory.createStore(factoryType, 0));
  867. List entries = new ArrayList(tjpFields.entrySet());
  868. Collections.sort(entries, new Comparator() {
  869. public int compare(Object a, Object b) {
  870. Map.Entry ae = (Map.Entry) a;
  871. Map.Entry be = (Map.Entry) b;
  872. return ((Field) ae.getValue())
  873. .getName()
  874. .compareTo(((Field)be.getValue()).getName());
  875. }
  876. });
  877. for (Iterator i = entries.iterator(); i.hasNext(); ) {
  878. Map.Entry entry = (Map.Entry)i.next();
  879. initializeTjp(fact, list, (Field)entry.getValue(), (BcelShadow)entry.getKey());
  880. }
  881. return list;
  882. }
  883. private void initializeTjp(InstructionFactory fact, InstructionList list,
  884. Field field, BcelShadow shadow)
  885. {
  886. Member sig = shadow.getSignature();
  887. //ResolvedMember mem = shadow.getSignature().resolve(shadow.getWorld());
  888. // load the factory
  889. list.append(InstructionFactory.createLoad(factoryType, 0));
  890. // load the kind
  891. list.append(InstructionFactory.PUSH(getConstantPool(), shadow.getKind().getName()));
  892. // create the signature
  893. list.append(InstructionFactory.createLoad(factoryType, 0));
  894. if (world.isTargettingAspectJRuntime12()) { // TAG:SUPPORTING12: We didn't have optimized factory methods in 1.2
  895. list.append(InstructionFactory.PUSH(getConstantPool(), sig.getSignatureString(shadow.getWorld())));
  896. list.append(fact.createInvoke(factoryType.getClassName(),
  897. sig.getSignatureMakerName(),
  898. new ObjectType(sig.getSignatureType()),
  899. new Type[] { Type.STRING },
  900. Constants.INVOKEVIRTUAL));
  901. } else if (sig.getKind().equals(Member.METHOD)) {
  902. BcelWorld w = shadow.getWorld();
  903. // For methods, push the parts of the signature on.
  904. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getModifiers(w))));
  905. list.append(InstructionFactory.PUSH(getConstantPool(),sig.getName()));
  906. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getDeclaringType())));
  907. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getParameterTypes())));
  908. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getParameterNames(w))));
  909. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getExceptions(w))));
  910. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getReturnType())));
  911. // And generate a call to the variant of makeMethodSig() that takes 7 strings
  912. list.append(fact.createInvoke(factoryType.getClassName(),
  913. sig.getSignatureMakerName(),
  914. new ObjectType(sig.getSignatureType()),
  915. new Type[] { Type.STRING,Type.STRING,Type.STRING,Type.STRING,Type.STRING,Type.STRING,Type.STRING },
  916. Constants.INVOKEVIRTUAL));
  917. } else if (sig.getKind().equals(Member.MONITORENTER)) {
  918. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getDeclaringType())));
  919. list.append(fact.createInvoke(factoryType.getClassName(),
  920. sig.getSignatureMakerName(),
  921. new ObjectType(sig.getSignatureType()),
  922. new Type[] { Type.STRING},
  923. Constants.INVOKEVIRTUAL));
  924. } else if (sig.getKind().equals(Member.MONITOREXIT)) {
  925. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getDeclaringType())));
  926. list.append(fact.createInvoke(factoryType.getClassName(),
  927. sig.getSignatureMakerName(),
  928. new ObjectType(sig.getSignatureType()),
  929. new Type[] { Type.STRING},
  930. Constants.INVOKEVIRTUAL));
  931. } else if (sig.getKind().equals(Member.HANDLER)) {
  932. BcelWorld w = shadow.getWorld();
  933. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getDeclaringType())));
  934. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getParameterTypes())));
  935. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getParameterNames(w))));
  936. list.append(fact.createInvoke(factoryType.getClassName(),
  937. sig.getSignatureMakerName(),
  938. new ObjectType(sig.getSignatureType()),
  939. new Type[] { Type.STRING, Type.STRING, Type.STRING },
  940. Constants.INVOKEVIRTUAL));
  941. } else if(sig.getKind().equals(Member.CONSTRUCTOR)) {
  942. BcelWorld w = shadow.getWorld();
  943. if (w.isJoinpointArrayConstructionEnabled() && sig.getDeclaringType().isArray()) {
  944. // its the magical new jp
  945. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(Modifier.PUBLIC)));
  946. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getDeclaringType())));
  947. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getParameterTypes())));
  948. list.append(InstructionFactory.PUSH(getConstantPool(),""));//makeString("")));//sig.getParameterNames(w))));
  949. list.append(InstructionFactory.PUSH(getConstantPool(),""));//makeString("")));//sig.getExceptions(w))));
  950. list.append(fact.createInvoke(factoryType.getClassName(),
  951. sig.getSignatureMakerName(),
  952. new ObjectType(sig.getSignatureType()),
  953. new Type[] { Type.STRING, Type.STRING, Type.STRING, Type.STRING, Type.STRING },
  954. Constants.INVOKEVIRTUAL));
  955. } else {
  956. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getModifiers(w))));
  957. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getDeclaringType())));
  958. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getParameterTypes())));
  959. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getParameterNames(w))));
  960. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getExceptions(w))));
  961. list.append(fact.createInvoke(factoryType.getClassName(),
  962. sig.getSignatureMakerName(),
  963. new ObjectType(sig.getSignatureType()),
  964. new Type[] { Type.STRING, Type.STRING, Type.STRING, Type.STRING, Type.STRING },
  965. Constants.INVOKEVIRTUAL));
  966. }
  967. } else if(sig.getKind().equals(Member.FIELD)) {
  968. BcelWorld w = shadow.getWorld();
  969. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getModifiers(w))));
  970. list.append(InstructionFactory.PUSH(getConstantPool(),sig.getName()));
  971. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getDeclaringType())));
  972. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getReturnType())));
  973. list.append(fact.createInvoke(factoryType.getClassName(),
  974. sig.getSignatureMakerName(),
  975. new ObjectType(sig.getSignatureType()),
  976. new Type[] { Type.STRING, Type.STRING, Type.STRING, Type.STRING },
  977. Constants.INVOKEVIRTUAL));
  978. } else if(sig.getKind().equals(Member.ADVICE)) {
  979. BcelWorld w = shadow.getWorld();
  980. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getModifiers(w))));
  981. list.append(InstructionFactory.PUSH(getConstantPool(),sig.getName()));
  982. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getDeclaringType())));
  983. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getParameterTypes())));
  984. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getParameterNames(w))));
  985. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getExceptions(w))));
  986. list.append(InstructionFactory.PUSH(getConstantPool(),makeString((sig.getReturnType()))));
  987. list.append(fact.createInvoke(factoryType.getClassName(),
  988. sig.getSignatureMakerName(),
  989. new ObjectType(sig.getSignatureType()),
  990. new Type[] { Type.STRING, Type.STRING, Type.STRING, Type.STRING, Type.STRING, Type.STRING, Type.STRING },
  991. Constants.INVOKEVIRTUAL));
  992. } else if(sig.getKind().equals(Member.STATIC_INITIALIZATION)) {
  993. BcelWorld w = shadow.getWorld();
  994. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getModifiers(w))));
  995. list.append(InstructionFactory.PUSH(getConstantPool(),makeString(sig.getDeclaringType())));
  996. list.append(fact.createInvoke(factoryType.getClassName(),
  997. sig.getSignatureMakerName(),
  998. new ObjectType(sig.getSignatureType()),
  999. new Type[] { Type.STRING, Type.STRING },
  1000. Constants.INVOKEVIRTUAL));
  1001. } else {
  1002. list.append(InstructionFactory.PUSH(getConstantPool(), sig.getSignatureString(shadow.getWorld())));
  1003. list.append(fact.createInvoke(factoryType.getClassName(),
  1004. sig.getSignatureMakerName(),
  1005. new ObjectType(sig.getSignatureType()),
  1006. new Type[] { Type.STRING },
  1007. Constants.INVOKEVIRTUAL));
  1008. }
  1009. //XXX should load source location from shadow
  1010. list.append(Utility.createConstant(fact, shadow.getSourceLine()));
  1011. final String factoryMethod;
  1012. if (world.isTargettingAspectJRuntime12()) { // TAG:SUPPORTING12: We didn't have makeESJP() in 1.2
  1013. list.append(fact.createInvoke(factoryType.getClassName(),
  1014. "makeSJP", staticTjpType,
  1015. new Type[] { Type.STRING, sigType, Type.INT},
  1016. Constants.INVOKEVIRTUAL));
  1017. // put it in the field
  1018. list.append(fact.createFieldAccess(getClassName(), field.getName(),staticTjpType, Constants.PUTSTATIC));
  1019. } else {
  1020. if (staticTjpType.equals(field.getType())) {
  1021. factoryMethod = "makeSJP";
  1022. } else if (enclosingStaticTjpType.equals(field.getType())) {
  1023. factoryMethod = "makeESJP";
  1024. } else {
  1025. throw new Error("should not happen");
  1026. }
  1027. list.append(fact.createInvoke(factoryType.getClassName(),
  1028. factoryMethod, field.getType(),
  1029. new Type[] { Type.STRING, sigType, Type.INT},
  1030. Constants.INVOKEVIRTUAL));
  1031. // put it in the field
  1032. list.append(fact.createFieldAccess(getClassName(), field.getName(), field.getType(), Constants.PUTSTATIC));
  1033. }
  1034. }
  1035. protected String makeString(int i) {
  1036. return Integer.toString(i, 16); //??? expensive
  1037. }
  1038. protected String makeString(UnresolvedType t) {
  1039. // this is the inverse of the odd behavior for Class.forName w/ arrays
  1040. if (t.isArray()) {
  1041. // this behavior matches the string used by the eclipse compiler for Foo.class literals
  1042. return t.getSignature().replace('/', '.');
  1043. } else {
  1044. return t.getName();
  1045. }
  1046. }
  1047. protected String makeString(UnresolvedType[] types) {
  1048. if (types == null) return "";
  1049. StringBuffer buf = new StringBuffer();
  1050. for (int i = 0, len=types.length; i < len; i++) {
  1051. buf.append(makeString(types[i]));
  1052. buf.append(':');
  1053. }
  1054. return buf.toString();
  1055. }
  1056. protected String makeString(String[] names) {
  1057. if (names == null) return "";
  1058. StringBuffer buf = new StringBuffer();
  1059. for (int i = 0, len=names.length; i < len; i++) {
  1060. buf.append(names[i]);
  1061. buf.append(':');
  1062. }
  1063. return buf.toString();
  1064. }
  1065. public ResolvedType getType() {
  1066. if (myType == null) return null;
  1067. return myType.getResolvedTypeX();
  1068. }
  1069. public BcelObjectType getBcelObjectType() {
  1070. return myType;
  1071. }
  1072. public String getFileName() {
  1073. return myGen.getFileName();
  1074. }
  1075. // for *new* fields
  1076. private void addField(FieldGen field) {
  1077. makeSyntheticAndTransientIfNeeded(field);
  1078. BcelField bcelField = null;
  1079. if (getBcelObjectType() != null) {
  1080. bcelField = new BcelField(getBcelObjectType(),field.getField());
  1081. } else {
  1082. bcelField = new BcelField(getName(),field.getField(),world);
  1083. }
  1084. fields.add(bcelField);
  1085. // myGen.addField(field.getField());
  1086. }
  1087. private void makeSyntheticAndTransientIfNeeded(FieldGen field) {
  1088. if (field.getName().startsWith(NameMangler.PREFIX) &&
  1089. !field.getName().startsWith("ajc$interField$") &&
  1090. !field.getName().startsWith("ajc$instance$")) {
  1091. // it's an aj added field
  1092. // first do transient
  1093. if (!field.isStatic()) {
  1094. field.setModifiers(field.getModifiers() | Constants.ACC_TRANSIENT);
  1095. }
  1096. // then do synthetic
  1097. if (getWorld().isInJava5Mode()) {
  1098. // add the synthetic modifier flag
  1099. field.setModifiers(field.getModifiers() | ACC_SYNTHETIC);
  1100. }
  1101. if (!hasSyntheticAttribute(field.getAttributes())) {
  1102. // belt and braces, do the attribute even on Java 5 in addition to the modifier flag
  1103. // Attribute[] oldAttrs = field.getAttributes();
  1104. // Attribute[] newAttrs = new Attribute[oldAttrs.length + 1];
  1105. // System.arraycopy(oldAttrs, 0, newAttrs, 0, oldAttrs.length);
  1106. ConstantPool cpg = myGen.getConstantPool();
  1107. int index = cpg.addUtf8("Synthetic");
  1108. Attribute synthetic = new Synthetic(index, 0, new byte[0], cpg);
  1109. field.addAttribute(synthetic);
  1110. // newAttrs[newAttrs.length - 1] = synthetic;
  1111. // field.setAttributes(newAttrs);
  1112. }
  1113. }
  1114. }
  1115. private boolean hasSyntheticAttribute(List attributes) {
  1116. for (int i = 0; i < attributes.size(); i++) {
  1117. if (((Attribute)attributes.get(i)).getName().equals("Synthetic")) {
  1118. return true;
  1119. }
  1120. }
  1121. return false;
  1122. }
  1123. public void addField(FieldGen field, ISourceLocation sourceLocation) {
  1124. addField(field);
  1125. if (!(field.isPrivate()
  1126. && (field.isStatic() || field.isTransient()))) {
  1127. errorOnAddedField(field,sourceLocation);
  1128. }
  1129. }
  1130. public String getClassName() {
  1131. return myGen.getClassName();
  1132. }
  1133. public boolean isInterface() {
  1134. return myGen.isInterface();
  1135. }
  1136. public boolean isAbstract() {
  1137. return myGen.isAbstract();
  1138. }
  1139. public LazyMethodGen getLazyMethodGen(Member m) {
  1140. return getLazyMethodGen(m.getName(), m.getSignature(),false);
  1141. }
  1142. public LazyMethodGen getLazyMethodGen(String name, String signature) {
  1143. return getLazyMethodGen(name,signature,false);
  1144. }
  1145. public LazyMethodGen getLazyMethodGen(String name, String signature,boolean allowMissing) {
  1146. for (Iterator i = methodGens.iterator(); i.hasNext();) {
  1147. LazyMethodGen gen = (LazyMethodGen) i.next();
  1148. if (gen.getName().equals(name) && gen.getSignature().equals(signature))
  1149. return gen;
  1150. }
  1151. if (!allowMissing) {
  1152. throw new BCException("Class " + this.getName() + " does not have a method "
  1153. + name + " with signature " + signature);
  1154. }
  1155. return null;
  1156. }
  1157. public void forcePublic() {
  1158. myGen.setModifiers(Utility.makePublic(myGen.getModifiers()));
  1159. }
  1160. public boolean hasAnnotation(UnresolvedType t) {
  1161. // annotations on the real thing
  1162. AnnotationGen agens[] = myGen.getAnnotations();
  1163. if (agens==null) return false;
  1164. for (int i = 0; i < agens.length; i++) {
  1165. AnnotationGen gen = agens[i];
  1166. if (t.equals(UnresolvedType.forSignature(gen.getTypeSignature()))) return true;
  1167. }
  1168. // annotations added during this weave
  1169. return false;
  1170. }
  1171. public void addAnnotation(AnnotationGen a) {
  1172. if (!hasAnnotation(UnresolvedType.forSignature(a.getTypeSignature()))) {
  1173. annotations.add(new AnnotationGen(a,getConstantPool(),true));
  1174. }
  1175. }
  1176. // this test is like asking:
  1177. // if (UnresolvedType.SERIALIZABLE.resolve(getType().getWorld()).isAssignableFrom(getType())) {
  1178. // only we don't do that because this forces us to find all the supertypes of the type,
  1179. // and if one of them is missing we fail, and it's not worth failing just to put out
  1180. // a warning message!
  1181. private boolean implementsSerializable(ResolvedType aType) {
  1182. if (aType.getSignature().equals(UnresolvedType.SERIALIZABLE.getSignature())) return true;
  1183. ResolvedType[] interfaces = aType.getDeclaredInterfaces();
  1184. for (int i = 0; i < interfaces.length; i++) {
  1185. if (interfaces[i].isMissing()) continue;
  1186. if (implementsSerializable(interfaces[i])) return true;
  1187. }
  1188. ResolvedType superType = aType.getSuperclass();
  1189. if (superType != null && !superType.isMissing()) {
  1190. return implementsSerializable(superType);
  1191. }
  1192. return false;
  1193. }
  1194. public boolean isAtLeastJava5() {
  1195. return (myGen.getMajor()>=Constants.MAJOR_1_5);
  1196. }
  1197. /**
  1198. * Return the next available field name with the specified 'prefix', e.g.
  1199. * for prefix 'class$' where class$0, class$1 exist then return class$2
  1200. */
  1201. public String allocateField(String prefix) {
  1202. int highestAllocated = -1;
  1203. List/*BcelField*/ fs = getFieldGens();
  1204. for (int i = 0; i < fs.size(); i++) {
  1205. BcelField field = (BcelField)fs.get(i);
  1206. if (field.getName().startsWith(prefix)) {
  1207. try {
  1208. int num = Integer.parseInt(field.getName().substring(prefix.length()));
  1209. if (num>highestAllocated) highestAllocated = num;
  1210. } catch (NumberFormatException nfe) {
  1211. // something wrong with the number on the end of that field...
  1212. }
  1213. }
  1214. }
  1215. return prefix+Integer.toString(highestAllocated+1);
  1216. }
  1217. }