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.

AjPipeliningCompilerAdapter.java 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. /*******************************************************************************
  2. * Copyright (c) 2006 IBM Corporation and others.
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * http://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors:
  9. * Andy Clement - initial implementation 26Jul06
  10. *******************************************************************************/
  11. package org.aspectj.ajdt.internal.compiler;
  12. import java.io.IOException;
  13. import java.util.ArrayList;
  14. import java.util.HashMap;
  15. import java.util.Hashtable;
  16. import java.util.Iterator;
  17. import java.util.List;
  18. import java.util.Map;
  19. import org.aspectj.ajdt.internal.compiler.ast.AddAtAspectJAnnotationsVisitor;
  20. import org.aspectj.ajdt.internal.compiler.ast.AspectDeclaration;
  21. import org.aspectj.ajdt.internal.compiler.ast.InterTypeConstructorDeclaration;
  22. import org.aspectj.ajdt.internal.compiler.ast.InterTypeFieldDeclaration;
  23. import org.aspectj.ajdt.internal.compiler.ast.InterTypeMethodDeclaration;
  24. import org.aspectj.ajdt.internal.compiler.ast.ValidateAtAspectJAnnotationsVisitor;
  25. import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
  26. import org.aspectj.ajdt.internal.core.builder.AjState;
  27. import org.aspectj.asm.internal.CharOperation;
  28. import org.aspectj.bridge.IMessage;
  29. import org.aspectj.bridge.IMessageHandler;
  30. import org.aspectj.bridge.IProgressListener;
  31. import org.aspectj.bridge.context.CompilationAndWeavingContext;
  32. import org.aspectj.bridge.context.ContextToken;
  33. import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
  34. import org.aspectj.org.eclipse.jdt.internal.compiler.Compiler;
  35. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
  36. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
  37. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
  38. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
  39. import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
  40. import org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
  41. import org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
  42. import org.aspectj.weaver.bcel.BcelWeaver;
  43. import org.aspectj.weaver.bcel.BcelWorld;
  44. import org.aspectj.weaver.bcel.UnwovenClassFile;
  45. /**
  46. * Adapts standard JDT Compiler to add in AspectJ specific behaviours. This version implements pipelining - where files are compiled
  47. * and then woven immediately, unlike AjCompilerAdapter which compiles everything then weaves everything. (One small note: because
  48. * all aspects have to be known before weaving can take place, the weaving pipeline is 'stalled' until all aspects have been
  49. * compiled).
  50. *
  51. * The basic strategy is this:
  52. *
  53. * 1. diet parse all input source files - this is enough for us to implement ITD matching - this enables us to determine which are
  54. * aspects 2. sort the input files, aspects first - keep a note of how many files contain aspects 3. if there are aspects, mark the
  55. * pipeline as 'stalled' 3. repeat 3a. compile a file 3b. have we now compiled all aspects? NO - put file in a weave pending queue
  56. * YES- unstall the 'pipeline' 3c. is the pipeline stalled? NO - weave all pending files and this one YES- do nothing
  57. *
  58. * Complexities arise because of: - what does -XterminateAfterCompilation mean? since there is no stage where everything is compiled
  59. * and nothing is woven
  60. *
  61. *
  62. * Here is the compiler loop difference when pipelining.
  63. *
  64. * the old way: Finished diet parsing [C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java] Finished diet parsing
  65. * [C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java] > AjLookupEnvironment.completeTypeBindings() <
  66. * AjLookupEnvironment.completeTypeBindings() compiling C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java
  67. * >Compiler.process(C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java)
  68. * <Compiler.process(C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java) compiling
  69. * C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java
  70. * >Compiler.process(C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java)
  71. * <Compiler.process(C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java) >AjCompilerAdapter.weave()
  72. * >BcelWeaver.prepareForWeave <BcelWeaver.prepareForWeave woven class ClassOne (from
  73. * C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java) woven class ClassTwo (from
  74. * C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java) <AjCompilerAdapter.weave()
  75. *
  76. * the new way (see the compiling/weaving mixed up): Finished diet parsing
  77. * [C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java] Finished diet parsing
  78. * [C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java] >AjLookupEnvironment.completeTypeBindings()
  79. * <AjLookupEnvironment.completeTypeBindings() compiling C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java
  80. * >Compiler.process(C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java)
  81. * <Compiler.process(C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java) >AjCompilerAdapter.weave()
  82. * >BcelWeaver.prepareForWeave <BcelWeaver.prepareForWeave woven class ClassOne (from
  83. * C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java) <AjCompilerAdapter.weave() compiling
  84. * C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java
  85. * >Compiler.process(C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java)
  86. * <Compiler.process(C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java) >AjCompilerAdapter.weave() woven class ClassTwo
  87. * (from C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java) <AjCompilerAdapter.weave()
  88. *
  89. *
  90. */
  91. public class AjPipeliningCompilerAdapter extends AbstractCompilerAdapter {
  92. private Compiler compiler;
  93. private BcelWeaver weaver;
  94. private EclipseFactory eWorld;
  95. private boolean isBatchCompile;
  96. private boolean reportedErrors;
  97. private boolean isXTerminateAfterCompilation;
  98. private boolean proceedOnError;
  99. private boolean inJava5Mode;
  100. private boolean makeReflectable;
  101. private boolean noAtAspectJAnnotationProcessing;
  102. private IIntermediateResultsRequestor intermediateResultsRequestor;
  103. private IProgressListener progressListener;
  104. private IOutputClassFileNameProvider outputFileNameProvider;
  105. private IBinarySourceProvider binarySourceProvider;
  106. private WeaverMessageHandler weaverMessageHandler;
  107. private Map<String, List<UnwovenClassFile>> binarySourceSetForFullWeave = new HashMap<>();
  108. private ContextToken processingToken = null;
  109. private ContextToken resolvingToken = null;
  110. private ContextToken analysingToken = null;
  111. private ContextToken generatingToken = null;
  112. private AjState incrementalCompilationState;
  113. // Maintains a list of whats weaving - whilst the pipeline is stalled, this accumulates aspects.
  114. List<InterimCompilationResult> resultsPendingWeave = new ArrayList<>();
  115. // pipelining info
  116. private boolean pipelineStalled = true;
  117. private boolean weaverInitialized = false;
  118. private int toWaitFor;
  119. // If we determine we are going to drop back to a full build - don't need to tell the weaver to report adviceDidNotMatch
  120. private boolean droppingBackToFullBuild;
  121. /**
  122. * Create an adapter, and tell it everything it needs to now to drive the AspectJ parts of a compile cycle.
  123. *
  124. * @param compiler the JDT compiler that produces class files from source
  125. * @param isBatchCompile true if this is a full build (non-incremental)
  126. * @param world the bcelWorld used for type resolution during weaving
  127. * @param weaver the weaver
  128. * @param intRequestor recipient of interim compilation results from compiler (pre-weave)
  129. * @param outputFileNameProvider implementor of a strategy providing output file names for results
  130. * @param binarySourceEntries binary source that we didn't compile, but that we need to weave
  131. * @param resultSetForFullWeave if we are doing an incremental build, and the weaver determines that we need to weave the world,
  132. * this is the set of intermediate results that will be passed to the weaver.
  133. */
  134. public AjPipeliningCompilerAdapter(Compiler compiler, boolean isBatchCompile, BcelWorld world, BcelWeaver weaver,
  135. EclipseFactory eFactory, IIntermediateResultsRequestor intRequestor, IProgressListener progressListener,
  136. IOutputClassFileNameProvider outputFileNameProvider, IBinarySourceProvider binarySourceProvider,
  137. Map fullBinarySourceEntries, /* fileName |-> List<UnwovenClassFile> */
  138. boolean isXterminateAfterCompilation, boolean proceedOnError, boolean noAtAspectJProcessing, boolean makeReflectable,
  139. AjState incrementalCompilationState) {
  140. this.compiler = compiler;
  141. this.isBatchCompile = isBatchCompile;
  142. this.weaver = weaver;
  143. this.intermediateResultsRequestor = intRequestor;
  144. this.progressListener = progressListener;
  145. this.outputFileNameProvider = outputFileNameProvider;
  146. this.binarySourceProvider = binarySourceProvider;
  147. this.isXTerminateAfterCompilation = isXterminateAfterCompilation;
  148. this.proceedOnError = proceedOnError;
  149. this.binarySourceSetForFullWeave = fullBinarySourceEntries;
  150. this.eWorld = eFactory;
  151. this.inJava5Mode = false;
  152. this.makeReflectable = makeReflectable;
  153. this.noAtAspectJAnnotationProcessing = noAtAspectJProcessing;
  154. this.incrementalCompilationState = incrementalCompilationState;
  155. if (compiler.options.complianceLevel >= ClassFileConstants.JDK1_5) {
  156. inJava5Mode = true;
  157. }
  158. IMessageHandler msgHandler = world.getMessageHandler();
  159. // Do we need to reset the message handler or create a new one? (This saves a ton of memory lost on incremental compiles...)
  160. if (msgHandler instanceof WeaverMessageHandler) {
  161. ((WeaverMessageHandler) msgHandler).resetCompiler(compiler);
  162. weaverMessageHandler = (WeaverMessageHandler) msgHandler;
  163. } else {
  164. weaverMessageHandler = new WeaverMessageHandler(msgHandler, compiler);
  165. world.setMessageHandler(weaverMessageHandler);
  166. }
  167. }
  168. // the compilation lifecycle methods below are called in order as compilation progresses...
  169. /**
  170. * In a pipelining compilation system, we need to ensure aspects are through the pipeline first. Only when they are all through
  171. * (and therefore we know about all static/dynamic crosscutting) can be proceed to weave anything. Effectively the weaving part
  172. * of the pipeline stalls until all the aspects have been fully compiled. This method sorts the compilation units such that any
  173. * containing aspects are fully compiled first and it keeps a note on how long it should stall the pipeline before commencing
  174. * weaving.
  175. */
  176. public void afterDietParsing(CompilationUnitDeclaration[] units) {
  177. if (debugPipeline) {
  178. System.err.println("> afterDietParsing: there are " + (units == null ? 0 : units.length) + " units to sort");
  179. }
  180. if (!reportedErrors && units != null) {
  181. for (CompilationUnitDeclaration unit : units) {
  182. if (unit != null && unit.compilationResult != null && unit.compilationResult.hasErrors()) {
  183. reportedErrors = true;
  184. break; // TODO break or exit here?
  185. }
  186. }
  187. }
  188. // Break the units into two lists...
  189. List<CompilationUnitDeclaration> aspects = new ArrayList<>();
  190. List<CompilationUnitDeclaration> nonaspects = new ArrayList<>();
  191. for (CompilationUnitDeclaration unit : units) {
  192. if (containsAnAspect(unit)) {
  193. aspects.add(unit);
  194. } else {
  195. nonaspects.add(unit);
  196. }
  197. }
  198. // ...and put them back together, aspects first
  199. int posn = 0;
  200. for (CompilationUnitDeclaration aspect : aspects) {
  201. units[posn++] = aspect;
  202. }
  203. for (CompilationUnitDeclaration nonaspect : nonaspects) {
  204. units[posn++] = nonaspect;
  205. }
  206. // Work out how long to stall the pipeline
  207. toWaitFor = aspects.size();
  208. if (debugPipeline) {
  209. System.err.println("< afterDietParsing: stalling pipeline for " + toWaitFor + " source files");
  210. }
  211. // TESTING
  212. if (pipelineTesting) {
  213. if (pipelineOutput == null) {
  214. pipelineOutput = new Hashtable();
  215. }
  216. pipelineOutput.put("filesContainingAspects", new Integer(toWaitFor).toString());
  217. StringBuffer order = new StringBuffer();
  218. order.append("[");
  219. for (int i = 0; i < units.length; i++) {
  220. if (i != 0) {
  221. order.append(",");
  222. }
  223. CompilationUnitDeclaration declaration = units[i];
  224. String filename = new String(declaration.getFileName());
  225. int idx = filename.lastIndexOf('/');
  226. if (idx > 0) {
  227. filename = filename.substring(idx + 1);
  228. }
  229. idx = filename.lastIndexOf('\\');
  230. if (idx > 0) {
  231. filename = filename.substring(idx + 1);
  232. }
  233. order.append(filename);
  234. }
  235. order.append("]");
  236. pipelineOutput.put("weaveOrder", order.toString());
  237. }
  238. }
  239. public void beforeCompiling(ICompilationUnit[] sourceUnits) {
  240. resultsPendingWeave = new ArrayList<>();
  241. reportedErrors = false;
  242. droppingBackToFullBuild = false;
  243. }
  244. public void beforeProcessing(CompilationUnitDeclaration unit) {
  245. if (debugPipeline) {
  246. System.err.println("compiling " + new String(unit.getFileName()));
  247. }
  248. eWorld.showMessage(IMessage.INFO, "compiling " + new String(unit.getFileName()), null, null);
  249. processingToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_COMPILATION_UNIT, unit
  250. .getFileName());
  251. if (inJava5Mode && !noAtAspectJAnnotationProcessing) {
  252. ContextToken tok = CompilationAndWeavingContext.enteringPhase(
  253. CompilationAndWeavingContext.ADDING_AT_ASPECTJ_ANNOTATIONS, unit.getFileName());
  254. AddAtAspectJAnnotationsVisitor atAspectJVisitor = new AddAtAspectJAnnotationsVisitor(unit, makeReflectable);
  255. unit.traverse(atAspectJVisitor, unit.scope);
  256. CompilationAndWeavingContext.leavingPhase(tok);
  257. }
  258. }
  259. public void beforeResolving(CompilationUnitDeclaration unit) {
  260. resolvingToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.RESOLVING_COMPILATION_UNIT, unit
  261. .getFileName());
  262. }
  263. public void afterResolving(CompilationUnitDeclaration unit) {
  264. if (resolvingToken != null) {
  265. CompilationAndWeavingContext.leavingPhase(resolvingToken);
  266. }
  267. }
  268. public void beforeAnalysing(CompilationUnitDeclaration unit) {
  269. analysingToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.ANALYSING_COMPILATION_UNIT, unit
  270. .getFileName());
  271. if (inJava5Mode && !noAtAspectJAnnotationProcessing) {
  272. ValidateAtAspectJAnnotationsVisitor atAspectJVisitor = new ValidateAtAspectJAnnotationsVisitor(unit);
  273. unit.traverse(atAspectJVisitor, unit.scope);
  274. }
  275. }
  276. public void afterAnalysing(CompilationUnitDeclaration unit) {
  277. if (analysingToken != null) {
  278. CompilationAndWeavingContext.leavingPhase(analysingToken);
  279. }
  280. }
  281. public void beforeGenerating(CompilationUnitDeclaration unit) {
  282. generatingToken = CompilationAndWeavingContext.enteringPhase(
  283. CompilationAndWeavingContext.GENERATING_UNWOVEN_CODE_FOR_COMPILATION_UNIT, unit.getFileName());
  284. if (eWorld.pushinCollector != null) {
  285. if (unit.types != null && unit.types.length > 0) {
  286. for (int t = 0; t < unit.types.length; t++) {
  287. TypeDeclaration type = unit.types[t];
  288. if (type.methods != null) {
  289. for (int m = 0; m < type.methods.length; m++) {
  290. AbstractMethodDeclaration md = type.methods[m];
  291. if (md instanceof InterTypeMethodDeclaration) {
  292. InterTypeMethodDeclaration itmd = ((InterTypeMethodDeclaration) md);
  293. ITDMethodPrinter printer = new ITDMethodPrinter(itmd, md.scope);
  294. String s = printer.print();
  295. eWorld.pushinCollector.recordInterTypeMethodDeclarationCode(md, s, getDeclarationLineNumber(md));
  296. } else if (md instanceof InterTypeFieldDeclaration) {
  297. ITDFieldPrinter printer = new ITDFieldPrinter(((InterTypeFieldDeclaration) md), md.scope);
  298. String s = printer.print();
  299. eWorld.pushinCollector.recordInterTypeFieldDeclarationCode(md, s, getDeclarationLineNumber(md));
  300. } else if (md instanceof InterTypeConstructorDeclaration) {
  301. ITDConstructorPrinter printer = new ITDConstructorPrinter(((InterTypeConstructorDeclaration) md),
  302. md.scope);
  303. String s = printer.print();
  304. eWorld.pushinCollector.recordInterTypeConstructorDeclarationCode(md, s,
  305. getDeclarationLineNumber(md));
  306. // } else if (md instanceof DeclareAnnotationDeclaration) {
  307. // DeclareAnnotationDeclaration dad = (DeclareAnnotationDeclaration) md;
  308. // String value = new DeclareAnnotationsPrinter(dad, dad.scope).print();
  309. // eWorld.pushinCollector.recordDeclareAnnotationDeclarationCode(md, value);
  310. }
  311. }
  312. }
  313. }
  314. }
  315. eWorld.pushinCollector.setOutputFileNameProvider(outputFileNameProvider);
  316. }
  317. }
  318. /**
  319. * @return the line number for this declaration in the source code
  320. */
  321. private int getDeclarationLineNumber(AbstractMethodDeclaration md) {
  322. int sourceStart = md.sourceStart;
  323. int[] separators = md.compilationResult.lineSeparatorPositions;
  324. int declarationStartLine = 1;
  325. for (int separator : separators) {
  326. if (sourceStart < separator) {
  327. break;
  328. }
  329. declarationStartLine++;
  330. }
  331. return declarationStartLine;
  332. }
  333. public void afterGenerating(CompilationUnitDeclaration unit) {
  334. if (generatingToken != null) {
  335. CompilationAndWeavingContext.leavingPhase(generatingToken);
  336. }
  337. if (eWorld.pushinCollector != null) {
  338. eWorld.pushinCollector.dump(unit);
  339. }
  340. }
  341. public void afterCompiling(CompilationUnitDeclaration[] units) {
  342. this.eWorld.cleanup();
  343. if (!weaverInitialized) { // nothing got compiled, doesnt mean there is nothing to do... (binary weaving)
  344. if (!(isXTerminateAfterCompilation || (reportedErrors && !proceedOnError))) {
  345. // acceptResult(unit.compilationResult);
  346. // } else {
  347. try {
  348. if (weaveQueuedEntries()) {
  349. droppingBackToFullBuild = true;
  350. }
  351. } catch (IOException ex) {
  352. AbortCompilation ac = new AbortCompilation(null, ex);
  353. throw ac;
  354. }
  355. }
  356. }
  357. postWeave();
  358. try {
  359. // not great ... but one more check before we continue, see pr132314
  360. if (!reportedErrors && units != null) {
  361. for (CompilationUnitDeclaration unit : units) {
  362. if (unit != null && unit.compilationResult != null && unit.compilationResult.hasErrors()) {
  363. reportedErrors = true;
  364. break;
  365. }
  366. }
  367. }
  368. if (isXTerminateAfterCompilation || (reportedErrors && !proceedOnError)) {
  369. // no point weaving... just tell the requestor we're done
  370. notifyRequestor();
  371. } else {
  372. // weave(); // notification happens as weave progresses...
  373. // weaver.getWorld().flush(); // pr152257
  374. }
  375. // } catch (IOException ex) {
  376. // AbortCompilation ac = new AbortCompilation(null,ex);
  377. // throw ac;
  378. } catch (RuntimeException rEx) {
  379. if (rEx instanceof AbortCompilation) {
  380. throw rEx; // Don't wrap AbortCompilation exceptions!
  381. }
  382. // This will be unwrapped in Compiler.handleInternalException() and the nested
  383. // RuntimeException thrown back to the original caller - which is AspectJ
  384. // which will then then log it as a compiler problem.
  385. throw new AbortCompilation(true, rEx);
  386. }
  387. }
  388. public void afterProcessing(CompilationUnitDeclaration unit, int unitIndex) {
  389. CompilationAndWeavingContext.leavingPhase(processingToken);
  390. eWorld.finishedCompilationUnit(unit);
  391. InterimCompilationResult intRes = new InterimCompilationResult(unit.compilationResult, outputFileNameProvider);
  392. if (unit.compilationResult.hasErrors()) {
  393. reportedErrors = true;
  394. }
  395. if (intermediateResultsRequestor != null) {
  396. intermediateResultsRequestor.acceptResult(intRes);
  397. }
  398. if (unit.compilationResult.hasErrors() || (isXTerminateAfterCompilation || (reportedErrors && !proceedOnError))) {
  399. acceptResult(unit.compilationResult);
  400. } else {
  401. queueForWeaving(intRes);
  402. }
  403. }
  404. private void queueForWeaving(InterimCompilationResult intRes) {
  405. resultsPendingWeave.add(intRes);
  406. if (pipelineStalled) {
  407. if (resultsPendingWeave.size() >= toWaitFor) {
  408. pipelineStalled = false;
  409. }
  410. }
  411. if (pipelineStalled) {
  412. return;
  413. }
  414. try {
  415. if (weaveQueuedEntries()) {
  416. droppingBackToFullBuild = true;
  417. }
  418. } catch (IOException ex) {
  419. AbortCompilation ac = new AbortCompilation(null, ex);
  420. throw ac;
  421. }
  422. }
  423. /*
  424. * Called from the weaverAdapter once it has finished weaving the class files associated with a given compilation result.
  425. */
  426. public void acceptResult(CompilationResult result) {
  427. compiler.requestor.acceptResult(result.tagAsAccepted());
  428. if (compiler.unitsToProcess != null) {
  429. for (int i = 0; i < compiler.unitsToProcess.length; i++) {
  430. if (compiler.unitsToProcess[i] != null) {
  431. if (compiler.unitsToProcess[i].compilationResult == result) {
  432. compiler.unitsToProcess[i].cleanUp();
  433. compiler.unitsToProcess[i] = null;
  434. }
  435. }
  436. }
  437. }
  438. }
  439. // helper methods...
  440. // ==================================================================================
  441. private List<InterimCompilationResult> getBinarySourcesFrom(Map<String, List<UnwovenClassFile>> binarySourceEntries) {
  442. // Map is fileName |-> List<UnwovenClassFile>
  443. List<InterimCompilationResult> ret = new ArrayList<>();
  444. for (String sourceFileName : binarySourceEntries.keySet()) {
  445. List<UnwovenClassFile> unwovenClassFiles = binarySourceEntries.get(sourceFileName);
  446. // XXX - see bugs 57432,58679 - final parameter on next call should be "compiler.options.maxProblemsPerUnit"
  447. CompilationResult result = new CompilationResult(sourceFileName.toCharArray(), 0, 0, Integer.MAX_VALUE);
  448. result.noSourceAvailable();
  449. InterimCompilationResult binarySource = new InterimCompilationResult(result, unwovenClassFiles);
  450. ret.add(binarySource);
  451. }
  452. return ret;
  453. }
  454. private void notifyRequestor() {
  455. for (InterimCompilationResult iresult : resultsPendingWeave) {
  456. compiler.requestor.acceptResult(iresult.result().tagAsAccepted());
  457. }
  458. }
  459. /** Return true if we've decided to drop back to a full build (too much has changed) */
  460. private boolean weaveQueuedEntries() throws IOException {
  461. if (debugPipeline) {
  462. System.err.println(">.weaveQueuedEntries()");
  463. }
  464. for (InterimCompilationResult iresult : resultsPendingWeave) {
  465. for (int i = 0; i < iresult.unwovenClassFiles().length; i++) {
  466. weaver.addClassFile(iresult.unwovenClassFiles()[i], false);
  467. }
  468. }
  469. ensureWeaverInitialized(); // by doing this only once, are we saying needToReweaveWorld can't change once the aspects have
  470. // been stuffed into the weaver?
  471. if (weaver.needToReweaveWorld() && !isBatchCompile) {
  472. return true;
  473. }
  474. weaver.weave(new WeaverAdapter(this, weaverMessageHandler, progressListener));
  475. resultsPendingWeave.clear(); // dont need to do those again
  476. this.eWorld.minicleanup();
  477. if (debugPipeline) {
  478. System.err.println("<.weaveQueuedEntries()");
  479. }
  480. return false;
  481. }
  482. private void ensureWeaverInitialized() {
  483. if (weaverInitialized) {
  484. return;
  485. }
  486. weaverInitialized = true;
  487. weaver.setIsBatchWeave(isBatchCompile);
  488. weaver.prepareForWeave();
  489. if (weaver.needToReweaveWorld()) {
  490. if (!isBatchCompile) {
  491. // force full recompilation from source
  492. this.incrementalCompilationState.forceBatchBuildNextTimeAround();
  493. return;
  494. }
  495. resultsPendingWeave.addAll(getBinarySourcesFrom(binarySourceSetForFullWeave));
  496. } else {
  497. Map binarySourcesToAdd = binarySourceProvider.getBinarySourcesForThisWeave();
  498. resultsPendingWeave.addAll(getBinarySourcesFrom(binarySourcesToAdd));
  499. }
  500. }
  501. // private void weave() throws IOException {
  502. // if (debugPipeline)System.err.println("> weave()");
  503. // // ensure weaver state is set up correctly
  504. // for (Iterator iter = resultsPendingWeave.iterator(); iter.hasNext();) {
  505. // InterimCompilationResult iresult = (InterimCompilationResult) iter.next();
  506. // for (int i = 0; i < iresult.unwovenClassFiles().length; i++) {
  507. // weaver.addClassFile(iresult.unwovenClassFiles()[i]);
  508. // }
  509. // }
  510. //
  511. // weaver.setIsBatchWeave(isBatchCompile);
  512. // weaver.prepareForWeave();
  513. // if (weaver.needToReweaveWorld()) {
  514. // if (!isBatchCompile) {
  515. // //force full recompilation from source
  516. // this.incrementalCompilationState.forceBatchBuildNextTimeAround();
  517. // return;
  518. // }
  519. // resultsPendingWeave.addAll(getBinarySourcesFrom(binarySourceSetForFullWeave));
  520. // } else {
  521. // Map binarySourcesToAdd = binarySourceProvider.getBinarySourcesForThisWeave();
  522. // resultsPendingWeave.addAll(getBinarySourcesFrom(binarySourcesToAdd));
  523. // }
  524. //
  525. // try {
  526. // weaver.weave(new WeaverAdapter(this,weaverMessageHandler,progressListener));
  527. // } finally {
  528. // weaver.tidyUp();
  529. // IMessageHandler imh = weaver.getWorld().getMessageHandler();
  530. // if (imh instanceof WeaverMessageHandler)
  531. // ((WeaverMessageHandler)imh).resetCompiler(null);
  532. // }
  533. // if (debugPipeline)System.err.println("< weave()");
  534. // }
  535. private void postWeave() {
  536. if (debugPipeline) {
  537. System.err.println("> postWeave()");
  538. }
  539. IMessageHandler imh = weaver.getWorld().getMessageHandler();
  540. if (imh instanceof WeaverMessageHandler) {
  541. ((WeaverMessageHandler) imh).setCurrentResult(null);
  542. }
  543. if (!droppingBackToFullBuild) {
  544. weaver.allWeavingComplete();
  545. }
  546. weaver.tidyUp();
  547. if (imh instanceof WeaverMessageHandler) {
  548. ((WeaverMessageHandler) imh).resetCompiler(null);
  549. }
  550. if (debugPipeline) {
  551. System.err.println("< postWeave()");
  552. }
  553. }
  554. /**
  555. * Return true if the compilation unit declaration contains an aspect declaration (either code style or annotation style). It
  556. * must inspect the multiple types that may be in a compilation unit declaration and any inner types.
  557. */
  558. private boolean containsAnAspect(CompilationUnitDeclaration cud) {
  559. TypeDeclaration[] typeDecls = cud.types;
  560. if (typeDecls != null) {
  561. for (TypeDeclaration declaration : typeDecls) { // loop through top level types in the file
  562. if (isAspect(declaration)) {
  563. return true;
  564. }
  565. if (declaration.memberTypes != null) {
  566. TypeDeclaration[] memberTypes = declaration.memberTypes;
  567. for (TypeDeclaration memberType : memberTypes) { // loop through inner types
  568. if (containsAnAspect(memberType)) {
  569. return true;
  570. }
  571. }
  572. }
  573. }
  574. }
  575. return false;
  576. }
  577. private boolean containsAnAspect(TypeDeclaration tDecl) {
  578. if (isAspect(tDecl)) {
  579. return true;
  580. }
  581. if (tDecl.memberTypes != null) {
  582. TypeDeclaration[] memberTypes = tDecl.memberTypes;
  583. for (TypeDeclaration memberType : memberTypes) { // loop through inner types
  584. if (containsAnAspect(memberType)) {
  585. return true;
  586. }
  587. }
  588. }
  589. return false;
  590. }
  591. private static final char[] aspectSig = "Lorg/aspectj/lang/annotation/Aspect;".toCharArray();
  592. private boolean isAspect(TypeDeclaration declaration) {
  593. // avoid an NPE when something else is wrong in this system ... the real problem will be reported elsewhere
  594. if (declaration.staticInitializerScope == null) {
  595. return false;
  596. }
  597. if (declaration instanceof AspectDeclaration) {
  598. return true; // code style
  599. } else if (declaration.annotations != null) { // check for annotation style
  600. for (int index = 0; index < declaration.annotations.length; index++) {
  601. // Cause annotation resolution
  602. declaration.binding.getAnnotationTagBits();
  603. Annotation a = declaration.annotations[index];
  604. if (a.resolvedType == null) {
  605. continue; // another problem is being reported, so don't crash here
  606. }
  607. if (CharOperation.equals(a.resolvedType.signature(), aspectSig)) {
  608. return true;
  609. }
  610. }
  611. }
  612. return false;
  613. }
  614. // ---
  615. /**
  616. * SECRET: FOR TESTING - this can be used to collect information that tests can verify.
  617. */
  618. public static boolean pipelineTesting = false;
  619. public static Hashtable<String, String> pipelineOutput = null;
  620. // Keys into pipelineOutput:
  621. // compileOrder "[XXX,YYY]" a list of the order in which files will be woven (aspects should be first)
  622. // filesContainingAspects "NNN" how many input source files have aspects inside
  623. //
  624. public static String getPipelineDebugOutput(String key) {
  625. if (pipelineOutput == null) {
  626. return "";
  627. }
  628. return pipelineOutput.get(key);
  629. }
  630. private final static boolean debugPipeline = false;
  631. public List<InterimCompilationResult> getResultsPendingWeave() {
  632. return resultsPendingWeave;
  633. }
  634. }