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

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