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

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