From: acolyer Date: Mon, 15 Mar 2004 15:10:46 +0000 (+0000) Subject: move weaving to inside of the compiler.compile loop. X-Git-Tag: Root_ajdt_support~131 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=40680b6fe4d28b2d061fc4cf9b3efa6640c12f44;p=aspectj.git move weaving to inside of the compiler.compile loop. ensure messages are associated with source wherever possible --- diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjClassFile.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjClassFile.java new file mode 100644 index 000000000..ef4a4a415 --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjClassFile.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.aspectj.ajdt.internal.compiler; + +import org.eclipse.jdt.internal.compiler.ClassFile; + +/** + * @author colyer + * + * XXX lightweight subclass of ClassFile that only genuinely supports fileName and getBytes + * operations. This nasty hack enables us to keep the rest of the implementation much simpler. + */ +public class AjClassFile extends ClassFile { + char[] filename; + byte[] bytes; + + public AjClassFile(char[] fileName, byte[] byteCodes) { + this.filename = fileName; + bytes = byteCodes; + } + + public char[] fileName() { + return filename; + } + + public byte[] getBytes() { + return bytes; + } +} diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompiler.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompiler.java index 2fce1117f..fef05581c 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompiler.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompiler.java @@ -1,69 +1,656 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * All rights reserved. - * This program and the accompanying materials are made available - * under the terms of the Common Public License v1.0 - * which accompanies this distribution and is available at - * http://www.eclipse.org/legal/cpl-v10.html - * - * Contributors: - * PARC initial implementation - * ******************************************************************/ - - -package org.aspectj.ajdt.internal.compiler; - -import java.util.Map; - -import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory; -import org.aspectj.bridge.IMessage; -import org.eclipse.jdt.internal.compiler.Compiler; -import org.eclipse.jdt.internal.compiler.ICompilerRequestor; -import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; -import org.eclipse.jdt.internal.compiler.IProblemFactory; -import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.env.INameEnvironment; - - -public class AjCompiler extends Compiler { - - public AjCompiler( - INameEnvironment environment, - IErrorHandlingPolicy policy, - Map settings, - ICompilerRequestor requestor, - IProblemFactory problemFactory) { - super(environment, policy, settings, requestor, problemFactory); - } - - public AjCompiler( - INameEnvironment environment, - IErrorHandlingPolicy policy, - Map settings, - ICompilerRequestor requestor, - IProblemFactory problemFactory, - boolean parseLiteralExpressionsAsConstants) { - super( - environment, - policy, - settings, - requestor, - problemFactory, - parseLiteralExpressionsAsConstants); - } - - /** - * In addition to processing each compilation unit in the normal ways, - * we also need to do weaving for inter-type declarations. This - * must be done before we use the signatures of these types to do any - * name binding. - */ - public void process(CompilationUnitDeclaration unit, int i) { - EclipseFactory world = - EclipseFactory.fromLookupEnvironment(lookupEnvironment); - world.showMessage(IMessage.INFO, "compiling " + new String(unit.getFileName()), null, null); - super.process(unit, i); - - world.finishedCompilationUnit(unit); - } -} +///* ******************************************************************* +// * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). +// * All rights reserved. +// * This program and the accompanying materials are made available +// * under the terms of the Common Public License v1.0 +// * which accompanies this distribution and is available at +// * http://www.eclipse.org/legal/cpl-v10.html +// * +// * Contributors: +// * PARC initial implementation +// * ******************************************************************/ +// +// +//package org.aspectj.ajdt.internal.compiler; +// +//import java.io.IOException; +//import java.util.ArrayList; +//import java.util.Collection; +//import java.util.Collections; +//import java.util.Enumeration; +//import java.util.Hashtable; +//import java.util.Iterator; +//import java.util.List; +//import java.util.Map; +// +//import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory; +//import org.aspectj.ajdt.internal.compiler.lookup.EclipseSourceLocation; +//import org.aspectj.bridge.AbortException; +//import org.aspectj.bridge.IMessage; +//import org.aspectj.bridge.IMessageHandler; +//import org.aspectj.bridge.ISourceLocation; +//import org.aspectj.bridge.IMessage.Kind; +//import org.aspectj.weaver.IClassFileProvider; +//import org.aspectj.weaver.IWeaveRequestor; +//import org.aspectj.weaver.bcel.BcelWeaver; +//import org.aspectj.weaver.bcel.BcelWorld; +//import org.aspectj.weaver.bcel.Pause; +//import org.aspectj.weaver.bcel.UnwovenClassFile; +//import org.aspectj.weaver.bcel.UnwovenClassFileWithThirdPartyManagedBytecode; +//import org.eclipse.jdt.core.compiler.IProblem; +//import org.eclipse.jdt.internal.compiler.ClassFile; +//import org.eclipse.jdt.internal.compiler.CompilationResult; +//import org.eclipse.jdt.internal.compiler.Compiler; +//import org.eclipse.jdt.internal.compiler.ICompilerRequestor; +//import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; +//import org.eclipse.jdt.internal.compiler.IProblemFactory; +//import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +//import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; +//import org.eclipse.jdt.internal.compiler.env.INameEnvironment; +//import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; +//import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; +//import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; +// +// +//public class AjCompiler extends Compiler { +// +// private List /*InterimResult*/ resultsPendingWeave = new ArrayList(); +// private BcelWorld bcelWorld; +// private BcelWeaver bcelWeaver; +// private IIntermediateResultsRequestor intermediateResultRequestor; +// private IOutputClassFileNameProvider nameProvider; +// private List /**/ binarySources = new ArrayList(); +// private boolean skipTheWeavePhase = false; +// private boolean reportedErrors = false; +// private WeaverMessageHandler wmHandler; +// private boolean isBatchCompile = false; +// private Collection /*InterimResult*/ resultSetForFullWeave = Collections.EMPTY_LIST; +// +// public interface IIntermediateResultsRequestor { +// void acceptResult(InterimResult intRes); +// } +// +// public interface IOutputClassFileNameProvider { +// String getOutputClassFileName(char[] eclipseClassFileName, CompilationResult result); +// } +// +// public AjCompiler( +// INameEnvironment environment, +// IErrorHandlingPolicy policy, +// Map settings, +// ICompilerRequestor requestor, +// IProblemFactory problemFactory) { +// super(environment, policy, settings, requestor, problemFactory); +// } +// +// public AjCompiler( +// INameEnvironment environment, +// IErrorHandlingPolicy policy, +// Map settings, +// ICompilerRequestor requestor, +// IProblemFactory problemFactory, +// boolean parseLiteralExpressionsAsConstants) { +// super( +// environment, +// policy, +// settings, +// requestor, +// problemFactory, +// parseLiteralExpressionsAsConstants); +// } +// +// +// public void setWeaver(BcelWeaver weaver) { +// this.bcelWeaver = weaver; +// } +// +// public void setWorld(BcelWorld world) { +// this.bcelWorld = world; +// IMessageHandler msgHandler = world.getMessageHandler(); +// wmHandler = new WeaverMessageHandler(msgHandler); +// world.setMessageHandler(wmHandler); +// } +// +// public void prepareForBatchCompilation() { +// isBatchCompile = true; +// } +// +// public void setIntermediateResultsRequestor(IIntermediateResultsRequestor intReq) { +// this.intermediateResultRequestor = intReq; +// } +// +// public void setNoWeave(boolean noWeave) { +// skipTheWeavePhase = noWeave; +// } +// +// public void setFullWeaveResults(Collection compilationResults) { +// resultSetForFullWeave = compilationResults; +// } +// +// public void setOutputFileNameProvider(IOutputClassFileNameProvider p) { +// this.nameProvider = p; +// } +// +// public void addBinarySourceFiles(Map binarySourceEntries) { +// // Map is fileName |-> List +// for (Iterator binIter = binarySourceEntries.keySet().iterator(); binIter.hasNext();) { +// String sourceFileName = (String) binIter.next(); +// List unwovenClassFiles = (List) binarySourceEntries.get(sourceFileName); +// +// CompilationResult result = new CompilationResult(sourceFileName.toCharArray(),0,0,20); +// result.noSourceAvailable(); +// InterimResult binarySource = new InterimResult(result,nameProvider); +// binarySource.unwovenClassFiles = new UnwovenClassFile[unwovenClassFiles.size()]; +// int index = 0; +// for (Iterator iter = unwovenClassFiles.iterator(); iter.hasNext();) { +// UnwovenClassFile element = (UnwovenClassFile) iter.next(); +// binarySource.unwovenClassFiles[index] = element; +// AjClassFile ajcf = new AjClassFile(element.getClassName().replace('.', '/').toCharArray(), +// element.getBytes()); +// result.record(ajcf.fileName(),ajcf); +// index++; +// } +// binarySources.add(binarySource); +// } +// } +// +// +// /** +// * In addition to processing each compilation unit in the normal ways, +// * we also need to do weaving for inter-type declarations. This +// * must be done before we use the signatures of these types to do any +// * name binding. +// */ +// public void process(CompilationUnitDeclaration unit, int i) { +// EclipseFactory world = +// EclipseFactory.fromLookupEnvironment(lookupEnvironment); +// world.showMessage(IMessage.INFO, "compiling " + new String(unit.getFileName()), null, null); +// super.process(unit, i); +// +// world.finishedCompilationUnit(unit); +// } +// +// +// /* (non-Javadoc) +// * @see org.eclipse.jdt.internal.compiler.Compiler#compile(org.eclipse.jdt.internal.compiler.env.ICompilationUnit[]) +// * We override this method to defer handing of results to the caller until the weave phase has +// * completed too. That way the class files are in final form and all error messages relating to the +// * compilation unit have been reported (which is the contract the JDT expects from this method). +// */ +// public void compile(ICompilationUnit[] sourceUnits) { +// try { +// resultsPendingWeave = new ArrayList(); +// reportedErrors = false; +// super.compile(sourceUnits); +// Pause.pause("After super compile"); +// try { +// if (!(skipTheWeavePhase || reportedErrors)) { +// weaveResults(); +// Pause.pause("After weave"); +// } else { +// notifyRequestor(); // weaver notifies as it goes along... +// } +// } catch (IOException ex) { +// // TODO +// ex.printStackTrace(); +// } +// } finally { +// cleanup(); +// } +// } +// +// +// /* (non-Javadoc) +// * @see org.eclipse.jdt.internal.compiler.Compiler#registerCompilationResult(org.eclipse.jdt.internal.compiler.CompilationResult) +// */ +// protected void registerCompilationResult(int index, CompilationResult result) { +// InterimResult intRes = new InterimResult(result,nameProvider); +// resultsPendingWeave.add(intRes); +// if (result.hasErrors()) reportedErrors = true; +// if (intermediateResultRequestor != null) { +// intermediateResultRequestor.acceptResult(intRes); +// } +// } +// +// /* (non-Javadoc) +// * @see org.eclipse.jdt.internal.compiler.Compiler#reset() +// * Super does this too early for us... +// */ +// public void reset() { +// // no-op, super calls this too early for us... +// } +// +// /* (non-Javadoc) +// * @see org.eclipse.jdt.internal.compiler.Compiler#resolve(org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration, org.eclipse.jdt.internal.compiler.env.ICompilationUnit, boolean, boolean, boolean) +// */ +// public CompilationUnitDeclaration resolve(CompilationUnitDeclaration unit, +// ICompilationUnit sourceUnit, boolean verifyMethods, +// boolean analyzeCode, boolean generateCode) { +// // TODO include weave phase in resolution too... +// return super.resolve(unit, sourceUnit, verifyMethods, analyzeCode, +// generateCode); +// } +// +// +// // AspectJ helper methods, called from compile... +// private void weaveResults() throws IOException { +// // ensure weaver state is set up correctly +// for (Iterator iter = resultsPendingWeave.iterator(); iter.hasNext();) { +// InterimResult iresult = (InterimResult) iter.next(); +// for (int i = 0; i < iresult.unwovenClassFiles.length; i++) { +// bcelWeaver.addClassFile(iresult.unwovenClassFiles[i]); +// } +// } +// Pause.pause("After adding class files to weaver"); +// bcelWeaver.prepareForWeave(); +// Pause.pause("After preparing for weave"); +// if (isBatchCompile) { +// resultsPendingWeave.addAll(binarySources); +// // passed into the compiler, the set of classes in injars and inpath... +// } else if (bcelWeaver.needToReweaveWorld()) { +// addAllKnownClassesToWeaveList(); +// } +// Pause.pause("After adding binary sources to weaver"); +// bcelWeaver.weave(new WeaverAdaptor(this)); +// } +// +// private void notifyRequestor() { +// for (Iterator iter = resultsPendingWeave.iterator(); iter.hasNext();) { +// InterimResult iresult = (InterimResult) iter.next(); +// requestor.acceptResult(iresult.result.tagAsAccepted()); +// } +// } +// +// private void cleanup() { +// resultsPendingWeave = null; +// isBatchCompile = false; +// binarySources = new ArrayList(); +// resultSetForFullWeave = Collections.EMPTY_LIST; +// super.reset(); +// Pause.pause("After notify and cleanup"); +// } +// +// private void addAllKnownClassesToWeaveList() { +// // results pending weave already has some results from this (incremental) compile +// // add in results from any other source +// for (Iterator iter = resultSetForFullWeave.iterator(); iter.hasNext();) { +// InterimResult ir = (InterimResult) iter.next(); +// if (!resultsPendingWeave.contains(ir)) { // equality based on source file name... +// ir.result.hasBeenAccepted = false; // it may have been accepted before, start again +// resultsPendingWeave.add(ir); +// } +// } +// } +// +// // Helper class that feeds input to the weaver, and accepts results +// // ======================================================================================= +// private static class WeaverAdaptor implements IClassFileProvider, IWeaveRequestor, Iterator { +// +// private AjCompiler compiler; +// private Iterator resultIterator; +// private int classFileIndex = 0; +// private InterimResult nowProcessing; +// private InterimResult lastReturnedResult; +//// private CompilationResult lastAcceptedResult; +// private boolean finalPhase = false; +// +// +// public WeaverAdaptor(AjCompiler forCompiler) { this.compiler = forCompiler; } +// +// /* (non-Javadoc) +// * @see org.aspectj.weaver.IClassFileProvider#getClassFileIterator() +// */ +// public Iterator getClassFileIterator() { +// classFileIndex = 0; +// nowProcessing = null; +// lastReturnedResult = null; +// resultIterator = compiler.resultsPendingWeave.iterator(); +// return this; +// } +// /* (non-Javadoc) +// * @see org.aspectj.weaver.IClassFileProvider#getRequestor() +// */ +// public IWeaveRequestor getRequestor() { +// return this; +// } +// /* (non-Javadoc) +// * @see org.aspectj.weaver.IWeaveRequestor#acceptResult(org.aspectj.weaver.bcel.UnwovenClassFile) +// */ +// public void acceptResult(UnwovenClassFile result) { +// char[] key = result.getClassName().replace('.','/').toCharArray(); +// removeFromHashtable(lastReturnedResult.result.compiledTypes,key); +// String className = result.getClassName().replace('.', '/'); +// AjClassFile ajcf = new AjClassFile(className.toCharArray(), +// result.getBytes()); +// lastReturnedResult.result.record(ajcf.fileName(),ajcf); +//// if ( f(lastAcceptedResult != null) && (lastReturnedResult.result != lastAcceptedResult)) { +//// // we've got everything we need for lastAcceptedResult, push the result out +//// // and free up the memory. +//// finishedWith(lastAcceptedResult); +//// } +//// lastAcceptedResult = lastReturnedResult.result; +// } +// +// private void finishedWith(InterimResult result) { +// compiler.requestor.acceptResult(result.result.tagAsAccepted()); +// for (int i = 0; i < compiler.unitsToProcess.length; i++) { +// if (compiler.unitsToProcess[i] != null) { +// if (compiler.unitsToProcess[i].compilationResult == result.result) { +// compiler.unitsToProcess[i] = null; +// } +// } +// } +// } +// +// /* (non-Javadoc) +// * @see java.util.Iterator#hasNext() +// */ +// public boolean hasNext() { +// if (nowProcessing == null) { +// if (!resultIterator.hasNext()) return false; +// nowProcessing = (InterimResult) resultIterator.next(); +// classFileIndex = 0; +// } +// while (nowProcessing.unwovenClassFiles.length == 0 ) { +// if (!resultIterator.hasNext()) return false; +// nowProcessing = (InterimResult) resultIterator.next(); +// } +// if (classFileIndex < nowProcessing.unwovenClassFiles.length) { +// return true; +// } else { +// classFileIndex = 0; +// if (!resultIterator.hasNext()) return false; +// nowProcessing = (InterimResult) resultIterator.next(); +// while (nowProcessing.unwovenClassFiles.length == 0 ) { +// if (!resultIterator.hasNext()) return false; +// nowProcessing = (InterimResult) resultIterator.next(); +// } +// } +// return true; +// } +// /* (non-Javadoc) +// * @see java.util.Iterator#next() +// */ +// public Object next() { +// if (!hasNext()) return null; // sets up indices correctly +// if (finalPhase) { +// if ((lastReturnedResult != null) && (lastReturnedResult != nowProcessing)) { +// // we're done with the lastReturnedResult +// finishedWith(lastReturnedResult); +// } +// } +// lastReturnedResult = nowProcessing; +// compiler.wmHandler.setCurrentResult(nowProcessing.result); +// return nowProcessing.unwovenClassFiles[classFileIndex++]; +// } +// /* (non-Javadoc) +// * @see java.util.Iterator#remove() +// */ +// public void remove() { +// throw new UnsupportedOperationException(); +// } +// +// public void processingReweavableState() {} +// public void addingTypeMungers() {} +// public void weavingAspects() {} +// public void weavingClasses() {finalPhase = true;} +// public void weaveCompleted() { +// if ((lastReturnedResult != null) && (!lastReturnedResult.result.hasBeenAccepted)) { +// finishedWith(lastReturnedResult); +// } +// } +// +// private void removeFromHashtable(Hashtable table, char[] key) { +// // jdt uses char[] as a key in the hashtable, which is not very useful as equality is based on being +// // the same array, not having the same content. +// String skey = new String(key); +// char[] victim = null; +// for (Enumeration iter = table.keys(); iter.hasMoreElements();) { +// char[] thisKey = (char[]) iter.nextElement(); +// if (skey.equals(new String(thisKey))) { +// victim = thisKey; +// break; +// } +// } +// if (victim != null) { +// table.remove(victim); +// } +// } +//} +// +// // Holder for intermediate form (class files) +// // ======================================================================================= +// public static class InterimResult { +// public CompilationResult result; +// public UnwovenClassFile[] unwovenClassFiles; // longer term would be nice not to have two copies of +// // the byte codes, one in result.classFiles and another +// // in unwovenClassFiles; +// private AjCompiler.IOutputClassFileNameProvider nameGen; +//// public String[] classNames; // entry at index i is the name of the class at unwovenClassFiles[i] +//// public BcelObjectType[] classTypes; // entry at i is the resolved type of the class at unwovenClassFiles[i] +// public InterimResult(CompilationResult cr, AjCompiler.IOutputClassFileNameProvider np) { +// result = cr; +// nameGen = np; +// unwovenClassFiles = ClassFileBasedByteCodeProvider.unwovenClassFilesFor(result,nameGen); +// } +// +// public String fileName() { +// return new String(result.fileName); +// } +// +// public boolean equals(Object other) { +// if( other == null || !(other instanceof InterimResult)) { +// return false; +// } +// InterimResult ir = (InterimResult) other; +// return fileName().equals(ir.fileName()); +// } +// public int hashCode() { +// return fileName().hashCode(); +// } +// }; +// +// +// +// // XXX lightweight subclass of ClassFile that only genuinely supports fileName and getBytes +// // operations. +// // ========================================================================================= +// private static class AjClassFile extends ClassFile { +// +// char[] filename; +// byte[] bytes; +// +// public AjClassFile(char[] fileName, byte[] byteCodes) { +// this.filename = fileName; +// bytes = byteCodes; +// } +// +// public char[] fileName() { +// return filename; +// } +// +// public byte[] getBytes() { +// return bytes; +// } +// }; +// +// +// // Adaptor for ClassFiles that lets them act as the bytecode repository +// // for UnwovenClassFiles (asking a ClassFile for its bytes causes a +// // copy to be made). +// private static class ClassFileBasedByteCodeProvider +// implements UnwovenClassFileWithThirdPartyManagedBytecode.IByteCodeProvider { +// private ClassFile cf; +// +// public ClassFileBasedByteCodeProvider(ClassFile cf) { +// this.cf = cf; +// } +// +// public byte[] getBytes() { +// return cf.getBytes(); +// } +// +// public static UnwovenClassFile[] unwovenClassFilesFor(CompilationResult result, +// AjCompiler.IOutputClassFileNameProvider nameProvider) { +// ClassFile[] cfs = result.getClassFiles(); +// UnwovenClassFile[] ret = new UnwovenClassFile[cfs.length]; +// for (int i = 0; i < ret.length; i++) { +// ClassFileBasedByteCodeProvider p = new ClassFileBasedByteCodeProvider(cfs[i]); +// String fileName = nameProvider.getOutputClassFileName(cfs[i].fileName(), result); +// ret[i] = new UnwovenClassFileWithThirdPartyManagedBytecode(fileName,p); +// } +// return ret; +// } +// +// } +// +// // Inner class for handling messages produced by the weaver +// // ========================================================== +// +// private class WeaverMessageHandler implements IMessageHandler { +// IMessageHandler sink; +// CompilationResult currentlyWeaving; +// +// public WeaverMessageHandler(IMessageHandler handler) { +// this.sink = handler; +// } +// +// public void setCurrentResult(CompilationResult result) { +// currentlyWeaving = result; +// } +// +// public boolean handleMessage(IMessage message) throws AbortException { +// if (! (message.isError() || message.isWarning()) ) return sink.handleMessage(message); +// // we only care about warnings and errors here... +// ISourceLocation sLoc = message.getSourceLocation(); +// CompilationResult problemSource = currentlyWeaving; +// if (problemSource == null) { +// // must be a problem found during completeTypeBindings phase of begin to compile +// if (sLoc instanceof EclipseSourceLocation) { +// problemSource = ((EclipseSourceLocation)sLoc).getCompilationResult(); +// } +// if (problemSource == null) { +// // XXX this is ok for ajc, will have to do better for AJDT in time... +// return sink.handleMessage(message); +// } +// } +// int startPos = getStartPos(sLoc,problemSource); +// int endPos = getEndPos(sLoc,problemSource); +// int severity = message.isError() ? ProblemSeverities.Error : ProblemSeverities.Warning; +// char[] filename = problemSource.fileName; +// boolean usedBinarySourceFileName = false; +// if (problemSource.isFromBinarySource()) { +// if (sLoc != null) { +// filename = sLoc.getSourceFile().getPath().toCharArray(); +// usedBinarySourceFileName = true; +// } +// } +// ReferenceContext referenceContext = findReferenceContextFor(problemSource); +// IProblem problem = problemReporter.createProblem( +// filename, +// IProblem.Unclassified, +// new String[0], +// new String[] {message.getMessage()}, +// severity, +// startPos, +// endPos, +// sLoc != null ? sLoc.getLine() : 1, +// referenceContext, +// problemSource +// ); +// IProblem[] seeAlso = buildSeeAlsoProblems(message.getExtraSourceLocations(), +// problemSource, +// usedBinarySourceFileName); +// problem.setSeeAlsoProblems(seeAlso); +// if (message.getDetails() != null) { +// problem.setSupplementaryMessageInfo(message.getDetails()); +// } +// problemReporter.record(problem, problemSource, referenceContext); +// return true; +//// if (weavingPhase) { +//// return sink.handleMessage(message); +//// } else { +//// return true; // message will be reported back in compilation result later... +//// } +// } +// +// public boolean isIgnoring(Kind kind) { +// return sink.isIgnoring(kind); +// } +// +// private int getStartPos(ISourceLocation sLoc,CompilationResult result) { +// int pos = 0; +// if (sLoc == null) return 0; +// int line = sLoc.getLine(); +// if (sLoc instanceof EclipseSourceLocation) { +// pos = ((EclipseSourceLocation)sLoc).getStartPos(); +// } else { +// if (line <= 1) return 0; +// if (result != null) { +// if ((result.lineSeparatorPositions != null) && +// (result.lineSeparatorPositions.length >= (line-1))) { +// pos = result.lineSeparatorPositions[line-2] + 1; +// } +// } +// } +// return pos; +// } +// +// private int getEndPos(ISourceLocation sLoc,CompilationResult result) { +// int pos = 0; +// if (sLoc == null) return 0; +// int line = sLoc.getLine(); +// if (line <= 0) line = 1; +// if (sLoc instanceof EclipseSourceLocation) { +// pos = ((EclipseSourceLocation)sLoc).getEndPos(); +// } else { +// if (result != null) { +// if ((result.lineSeparatorPositions != null) && +// (result.lineSeparatorPositions.length >= line)) { +// pos = result.lineSeparatorPositions[line -1] -1; +// } +// } +// } +// return pos; +// } +// +// private ReferenceContext findReferenceContextFor(CompilationResult result) { +// ReferenceContext context = null; +// if (unitsToProcess == null) return null; +// for (int i = 0; i < unitsToProcess.length; i++) { +// if ((unitsToProcess[i] != null) && +// (unitsToProcess[i].compilationResult == result)) { +// context = unitsToProcess[i]; +// break; +// } +// } +// return context; +// } +// +// private IProblem[] buildSeeAlsoProblems(List sourceLocations, +// CompilationResult problemSource, +// boolean usedBinarySourceFileName) { +// int probLength = sourceLocations.size(); +// if (usedBinarySourceFileName) probLength++; +// IProblem[] ret = new IProblem[probLength]; +// for (int i = 0; i < sourceLocations.size(); i++) { +// ISourceLocation loc = (ISourceLocation) sourceLocations.get(i); +// ret[i] = new DefaultProblem(loc.getSourceFile().getPath().toCharArray(), +// "see also", +// 0, +// new String[] {}, +// ProblemSeverities.Ignore, +// getStartPos(loc,null), +// getEndPos(loc,null), +// loc.getLine()); +// } +// if (usedBinarySourceFileName) { +// ret[ret.length -1] = new DefaultProblem(problemSource.fileName,"see also",0,new String[] {}, +// ProblemSeverities.Ignore,0, +// 0,0); +// } +// return ret; +// } +// } +// +//} diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompilerAdapter.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompilerAdapter.java new file mode 100644 index 000000000..ab3cebdb2 --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompilerAdapter.java @@ -0,0 +1,231 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.aspectj.ajdt.internal.compiler; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory; +import org.aspectj.bridge.IMessage; +import org.aspectj.bridge.IMessageHandler; +import org.aspectj.weaver.bcel.BcelWeaver; +import org.aspectj.weaver.bcel.BcelWorld; +import org.eclipse.jdt.internal.compiler.CompilationResult; +import org.eclipse.jdt.internal.compiler.Compiler; +import org.eclipse.jdt.internal.compiler.ICompilerAdapter; +import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; +import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; + +/** + * @author colyer + * + * Adapts standard JDT Compiler to add in AspectJ specific behaviours. + */ +public class AjCompilerAdapter implements ICompilerAdapter { + + private Compiler compiler; + private BcelWeaver weaver; + private EclipseFactory eWorld; + private boolean isBatchCompile; + private boolean reportedErrors; + private boolean isXNoWeave; + private IIntermediateResultsRequestor intermediateResultsRequestor; + private IOutputClassFileNameProvider outputFileNameProvider; + private WeaverMessageHandler weaverMessageHandler; + private List /* InterimCompilationResult */ binarySources = new ArrayList(); + private Collection /*InterimCompilationResult*/ resultSetForFullWeave = Collections.EMPTY_LIST; + + + List /*InterimResult*/ resultsPendingWeave = new ArrayList(); + + /** + * Create an adapter, and tell it everything it needs to now to drive the AspectJ + * parts of a compile cycle. + * @param compiler the JDT compiler that produces class files from source + * @param isBatchCompile true if this is a full build (non-incremental) + * @param world the bcelWorld used for type resolution during weaving + * @param weaver the weaver + * @param intRequestor recipient of interim compilation results from compiler (pre-weave) + * @param outputFileNameProvider implementor of a strategy providing output file names for results + * @param binarySourceEntries binary source that we didn't compile, but that we need to weave + * @param resultSetForFullWeave if we are doing an incremental build, and the weaver determines + * that we need to weave the world, this is the set of intermediate + * results that will be passed to the weaver. + * @param isXNoWeave + */ + public AjCompilerAdapter(Compiler compiler, + boolean isBatchCompile, + BcelWorld world, + BcelWeaver weaver, + EclipseFactory eFactory, + IIntermediateResultsRequestor intRequestor, + IOutputClassFileNameProvider outputFileNameProvider, + Map binarySourceEntries, /* fileName |-> List */ + Collection /* InterimCompilationResult */ resultSetForFullWeave, + boolean isXNoWeave) { + this.compiler = compiler; + this.isBatchCompile = isBatchCompile; + this.weaver = weaver; + this.intermediateResultsRequestor = intRequestor; + this.outputFileNameProvider = outputFileNameProvider; + this.isXNoWeave = isXNoWeave; + this.resultSetForFullWeave = resultSetForFullWeave; + this.eWorld = eFactory; + + IMessageHandler msgHandler = world.getMessageHandler(); + weaverMessageHandler = new WeaverMessageHandler(msgHandler, compiler); + world.setMessageHandler(weaverMessageHandler); + + addBinarySource(binarySourceEntries); + } + + public void beforeCompiling(ICompilationUnit[] sourceUnits) { + resultsPendingWeave = new ArrayList(); + reportedErrors = false; + } + + public void afterCompiling() { + try { + if (isXNoWeave || reportedErrors) { + // no point weaving... just tell the requestor we're done + notifyRequestor(); + } else { + weave(); // notification happens as weave progresses... + } + } catch (IOException ex) { + AbortCompilation ac = new AbortCompilation(); + ac.initCause(ex); + throw ac; + } + } + + public void beforeProcessing(CompilationUnitDeclaration unit) { + eWorld.showMessage(IMessage.INFO, "compiling " + new String(unit.getFileName()), null, null); + } + + public void afterProcessing(CompilationUnitDeclaration unit, int unitIndex) { + eWorld.finishedCompilationUnit(unit); + InterimCompilationResult intRes = new InterimCompilationResult(unit.compilationResult,outputFileNameProvider); + if (unit.compilationResult.hasErrors()) reportedErrors = true; + + if (intermediateResultsRequestor != null) { + intermediateResultsRequestor.acceptResult(intRes); + } + + if (isXNoWeave) { + acceptResult(unit.compilationResult); + } else { + resultsPendingWeave.add(intRes); + } + } + + public void beforeResolving(CompilationUnitDeclaration unit, ICompilationUnit sourceUnit, boolean verifyMethods, boolean analyzeCode, boolean generateCode) { + resultsPendingWeave = new ArrayList(); + reportedErrors = false; + } + + public void afterResolving(CompilationUnitDeclaration unit, ICompilationUnit sourceUnit, boolean verifyMethods, boolean analyzeCode, boolean generateCode) { + InterimCompilationResult intRes = new InterimCompilationResult(unit.compilationResult,outputFileNameProvider); + if (unit.compilationResult.hasErrors()) reportedErrors = true; + if (isXNoWeave || !generateCode) { + acceptResult(unit.compilationResult); + } else if (generateCode){ + resultsPendingWeave.add(intRes); + try { + weave(); + } catch (IOException ex) { + AbortCompilation ac = new AbortCompilation(); + ac.initCause(ex); + throw ac; + } + } + } + + // helper methods... + // ================================================================================== + + /* + * Called from the weaverAdapter once it has finished weaving the class files + * associated with a given compilation result. + */ + public void acceptResult(CompilationResult result) { + compiler.requestor.acceptResult(result.tagAsAccepted()); + if (compiler.unitsToProcess != null) { + for (int i = 0; i < compiler.unitsToProcess.length; i++) { + if (compiler.unitsToProcess[i] != null) { + if (compiler.unitsToProcess[i].compilationResult == result) { + compiler.unitsToProcess[i] = null; + } + } + } + } + } + + private void addBinarySource(Map binarySourceEntries) { + // Map is fileName |-> List + for (Iterator binIter = binarySourceEntries.keySet().iterator(); binIter.hasNext();) { + String sourceFileName = (String) binIter.next(); + List unwovenClassFiles = (List) binarySourceEntries.get(sourceFileName); + + CompilationResult result = new CompilationResult(sourceFileName.toCharArray(),0,0,20); + result.noSourceAvailable(); + InterimCompilationResult binarySource = + new InterimCompilationResult(result,unwovenClassFiles); + binarySources.add(binarySource); + } + } + + private void notifyRequestor() { + for (Iterator iter = resultsPendingWeave.iterator(); iter.hasNext();) { + InterimCompilationResult iresult = (InterimCompilationResult) iter.next(); + compiler.requestor.acceptResult(iresult.result().tagAsAccepted()); + } + } + + private void weave() throws IOException { + // ensure weaver state is set up correctly + for (Iterator iter = resultsPendingWeave.iterator(); iter.hasNext();) { + InterimCompilationResult iresult = (InterimCompilationResult) iter.next(); + for (int i = 0; i < iresult.unwovenClassFiles().length; i++) { + weaver.addClassFile(iresult.unwovenClassFiles()[i]); + } + } + + weaver.prepareForWeave(); + + if (isBatchCompile) { + resultsPendingWeave.addAll(binarySources); + // passed into the compiler, the set of classes in injars and inpath... + } else if (weaver.needToReweaveWorld()) { + addAllKnownClassesToWeaveList(); + } + + weaver.weave(new WeaverAdapter(this,weaverMessageHandler)); + } + + private void addAllKnownClassesToWeaveList() { + // results pending weave already has some results from this (incremental) compile + // add in results from any other source + for (Iterator iter = resultSetForFullWeave.iterator(); iter.hasNext();) { + InterimCompilationResult ir = (InterimCompilationResult) iter.next(); + if (!resultsPendingWeave.contains(ir)) { // equality based on source file name... + ir.result().hasBeenAccepted = false; // it may have been accepted before, start again + resultsPendingWeave.add(ir); + } + } + } +} diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ClassFileBasedByteCodeProvider.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ClassFileBasedByteCodeProvider.java new file mode 100644 index 000000000..57a64a820 --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ClassFileBasedByteCodeProvider.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.aspectj.ajdt.internal.compiler; + +import org.aspectj.weaver.bcel.UnwovenClassFile; +import org.aspectj.weaver.bcel.UnwovenClassFileWithThirdPartyManagedBytecode; +import org.eclipse.jdt.internal.compiler.ClassFile; +import org.eclipse.jdt.internal.compiler.CompilationResult; + +/** + * @author colyer + * + * Adaptor for ClassFiles that lets them act as the bytecode repository + * for UnwovenClassFiles (asking a ClassFile for its bytes causes a + * copy to be made). + */ +public class ClassFileBasedByteCodeProvider + implements UnwovenClassFileWithThirdPartyManagedBytecode.IByteCodeProvider{ + + private ClassFile cf; + + public ClassFileBasedByteCodeProvider(ClassFile cf) { + this.cf = cf; + } + + public byte[] getBytes() { + return cf.getBytes(); + } + + public static UnwovenClassFile[] unwovenClassFilesFor(CompilationResult result, + IOutputClassFileNameProvider nameProvider) { + ClassFile[] cfs = result.getClassFiles(); + UnwovenClassFile[] ret = new UnwovenClassFile[cfs.length]; + for (int i = 0; i < ret.length; i++) { + ClassFileBasedByteCodeProvider p = new ClassFileBasedByteCodeProvider(cfs[i]); + String fileName = nameProvider.getOutputClassFileName(cfs[i].fileName(), result); + ret[i] = new UnwovenClassFileWithThirdPartyManagedBytecode(fileName,p); + } + return ret; + } + +} diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/IIntermediateResultsRequestor.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/IIntermediateResultsRequestor.java new file mode 100644 index 000000000..c97c20dc6 --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/IIntermediateResultsRequestor.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.aspectj.ajdt.internal.compiler; + +/** + * @author colyer + * + * Receives intermediate results from the compiler (post java-compile, but + * before weaving). + */ +public interface IIntermediateResultsRequestor { + void acceptResult(InterimCompilationResult intRes); +} diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/IOutputClassFileNameProvider.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/IOutputClassFileNameProvider.java new file mode 100644 index 000000000..125d9ce1b --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/IOutputClassFileNameProvider.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.aspectj.ajdt.internal.compiler; + +import org.eclipse.jdt.internal.compiler.CompilationResult; + +/** + * @author colyer + * + * Implementors of this interface know how to create an output destination name + * for a given compilation result and class file. This interface capures the variation + * in strategy between ajc command-line compiles and an AJDT driven compilation. + */ +public interface IOutputClassFileNameProvider { + String getOutputClassFileName(char[] eclipseClassFileName, CompilationResult result); +} diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/InterimCompilationResult.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/InterimCompilationResult.java new file mode 100644 index 000000000..3e72d7c3b --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/InterimCompilationResult.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.aspectj.ajdt.internal.compiler; + +import java.util.List; + +import org.aspectj.weaver.bcel.UnwovenClassFile; +import org.eclipse.jdt.internal.compiler.CompilationResult; + +/** + * Holds a compilation result produced by the Java compilation phase, + * ready for weaving in the weave phase. + * NOTE: This class defines equality based solely on the fileName + * of the compiled file (not the bytecodes produced for example) + */ +public class InterimCompilationResult { + + private CompilationResult result; + private UnwovenClassFile[] unwovenClassFiles; // longer term would be nice not to have two copies of + // the byte codes, one in result.classFiles and another + // in unwovenClassFiles; + + public InterimCompilationResult(CompilationResult cr, + IOutputClassFileNameProvider np) { + result = cr; + unwovenClassFiles = ClassFileBasedByteCodeProvider.unwovenClassFilesFor(result,np); + } + + public InterimCompilationResult(CompilationResult cr, List ucfList) { + result = cr; + unwovenClassFiles = new UnwovenClassFile[ucfList.size()]; + for (int i=0; i < ucfList.size(); i++) { + UnwovenClassFile element = (UnwovenClassFile) ucfList.get(i); + unwovenClassFiles[i] = element; + AjClassFile ajcf = new AjClassFile(element.getClassName().replace('.', '/').toCharArray(), + element.getBytes()); + result.record(ajcf.fileName(),ajcf); + } + } + + public CompilationResult result() { return result; } + + public UnwovenClassFile[] unwovenClassFiles() { return unwovenClassFiles; } + + public String fileName() { + return new String(result.fileName); + } + + public boolean equals(Object other) { + if( other == null || !(other instanceof InterimCompilationResult)) { + return false; + } + InterimCompilationResult ir = (InterimCompilationResult) other; + return fileName().equals(ir.fileName()); + } + public int hashCode() { + return fileName().hashCode(); + } + +} diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverAdapter.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverAdapter.java new file mode 100644 index 000000000..6eead0082 --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverAdapter.java @@ -0,0 +1,163 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.aspectj.ajdt.internal.compiler; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; + +import org.aspectj.weaver.IClassFileProvider; +import org.aspectj.weaver.IWeaveRequestor; +import org.aspectj.weaver.bcel.UnwovenClassFile; + +/** + * @author colyer + * This class provides the weaver with a source of class files to weave (via the + * iterator and IClassFileProvider interfaces). It receives results back from the + * weaver via the IWeaveRequestor interface. + */ +public class WeaverAdapter implements IClassFileProvider, IWeaveRequestor, Iterator { + + private AjCompilerAdapter compilerAdapter; + private Iterator resultIterator; + private int classFileIndex = 0; + private InterimCompilationResult nowProcessing; + private InterimCompilationResult lastReturnedResult; + private WeaverMessageHandler weaverMessageHandler; + private boolean finalPhase = false; + + + public WeaverAdapter(AjCompilerAdapter forCompiler, + WeaverMessageHandler weaverMessageHandler) { + this.compilerAdapter = forCompiler; + this.weaverMessageHandler = weaverMessageHandler; + } + + /* (non-Javadoc) + * @see org.aspectj.weaver.IClassFileProvider#getClassFileIterator() + */ + public Iterator getClassFileIterator() { + classFileIndex = 0; + nowProcessing = null; + lastReturnedResult = null; + resultIterator = compilerAdapter.resultsPendingWeave.iterator(); + return this; + } + /* (non-Javadoc) + * @see org.aspectj.weaver.IClassFileProvider#getRequestor() + */ + public IWeaveRequestor getRequestor() { + return this; + } + + // Iteration + // ================================================================ + + /* (non-Javadoc) + * @see java.util.Iterator#hasNext() + */ + public boolean hasNext() { + if (nowProcessing == null) { + if (!resultIterator.hasNext()) return false; + nowProcessing = (InterimCompilationResult) resultIterator.next(); + classFileIndex = 0; + } + while (nowProcessing.unwovenClassFiles().length == 0 ) { + if (!resultIterator.hasNext()) return false; + nowProcessing = (InterimCompilationResult) resultIterator.next(); + } + if (classFileIndex < nowProcessing.unwovenClassFiles().length) { + return true; + } else { + classFileIndex = 0; + if (!resultIterator.hasNext()) return false; + nowProcessing = (InterimCompilationResult) resultIterator.next(); + while (nowProcessing.unwovenClassFiles().length == 0 ) { + if (!resultIterator.hasNext()) return false; + nowProcessing = (InterimCompilationResult) resultIterator.next(); + } + } + return true; + } + /* (non-Javadoc) + * @see java.util.Iterator#next() + */ + public Object next() { + if (!hasNext()) return null; // sets up indices correctly + if (finalPhase) { + if ((lastReturnedResult != null) && (lastReturnedResult != nowProcessing)) { + // we're done with the lastReturnedResult + finishedWith(lastReturnedResult); + } + } + lastReturnedResult = nowProcessing; + weaverMessageHandler.setCurrentResult(nowProcessing.result()); + return nowProcessing.unwovenClassFiles()[classFileIndex++]; + } + /* (non-Javadoc) + * @see java.util.Iterator#remove() + */ + public void remove() { + throw new UnsupportedOperationException(); + } + + + // IWeaveRequestor + // ===================================================================================== + + // weave phases as indicated by bcelWeaver... + public void processingReweavableState() {} + public void addingTypeMungers() {} + public void weavingAspects() {} + public void weavingClasses() {finalPhase = true;} + + public void weaveCompleted() { + if ((lastReturnedResult != null) && (!lastReturnedResult.result().hasBeenAccepted)) { + finishedWith(lastReturnedResult); + } + } + + /* (non-Javadoc) + * @see org.aspectj.weaver.IWeaveRequestor#acceptResult(org.aspectj.weaver.bcel.UnwovenClassFile) + */ + public void acceptResult(UnwovenClassFile result) { + char[] key = result.getClassName().replace('.','/').toCharArray(); + removeFromHashtable(lastReturnedResult.result().compiledTypes,key); + String className = result.getClassName().replace('.', '/'); + AjClassFile ajcf = new AjClassFile(className.toCharArray(), + result.getBytes()); + lastReturnedResult.result().record(ajcf.fileName(),ajcf); + } + + // helpers... + // ================================================================= + + private void finishedWith(InterimCompilationResult result) { + compilerAdapter.acceptResult(result.result()); + } + + private void removeFromHashtable(Hashtable table, char[] key) { + // jdt uses char[] as a key in the hashtable, which is not very useful as equality is based on being + // the same array, not having the same content. + String skey = new String(key); + char[] victim = null; + for (Enumeration iter = table.keys(); iter.hasMoreElements();) { + char[] thisKey = (char[]) iter.nextElement(); + if (skey.equals(new String(thisKey))) { + victim = thisKey; + break; + } + } + if (victim != null) { + table.remove(victim); + } + } +} \ No newline at end of file diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverMessageHandler.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverMessageHandler.java new file mode 100644 index 000000000..399eddc95 --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverMessageHandler.java @@ -0,0 +1,176 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.aspectj.ajdt.internal.compiler; + +import java.util.List; + +import org.aspectj.ajdt.internal.compiler.lookup.EclipseSourceLocation; +import org.aspectj.bridge.AbortException; +import org.aspectj.bridge.IMessage; +import org.aspectj.bridge.IMessageHandler; +import org.aspectj.bridge.ISourceLocation; +import org.aspectj.bridge.IMessage.Kind; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.CompilationResult; +import org.eclipse.jdt.internal.compiler.Compiler; +import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; +import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; +import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; + +/** + * @author colyer + * + * To change the template for this generated type comment go to + * Window>Preferences>Java>Code Generation>Code and Comments + */ +public class WeaverMessageHandler implements IMessageHandler { + private IMessageHandler sink; + private CompilationResult currentlyWeaving; + private Compiler compiler; + + public WeaverMessageHandler(IMessageHandler handler, Compiler compiler) { + this.sink = handler; + this.compiler = compiler; + } + + public void setCurrentResult(CompilationResult result) { + currentlyWeaving = result; + } + + public boolean handleMessage(IMessage message) throws AbortException { + if (! (message.isError() || message.isWarning()) ) return sink.handleMessage(message); + // we only care about warnings and errors here... + ISourceLocation sLoc = message.getSourceLocation(); + CompilationResult problemSource = currentlyWeaving; + if (problemSource == null) { + // must be a problem found during completeTypeBindings phase of begin to compile + if (sLoc instanceof EclipseSourceLocation) { + problemSource = ((EclipseSourceLocation)sLoc).getCompilationResult(); + } + if (problemSource == null) { + // XXX this is ok for ajc, will have to do better for AJDT in time... + return sink.handleMessage(message); + } + } + int startPos = getStartPos(sLoc,problemSource); + int endPos = getEndPos(sLoc,problemSource); + int severity = message.isError() ? ProblemSeverities.Error : ProblemSeverities.Warning; + char[] filename = problemSource.fileName; + boolean usedBinarySourceFileName = false; + if (problemSource.isFromBinarySource()) { + if (sLoc != null) { + filename = sLoc.getSourceFile().getPath().toCharArray(); + usedBinarySourceFileName = true; + } + } + ReferenceContext referenceContext = findReferenceContextFor(problemSource); + IProblem problem = compiler.problemReporter.createProblem( + filename, + IProblem.Unclassified, + new String[0], + new String[] {message.getMessage()}, + severity, + startPos, + endPos, + sLoc != null ? sLoc.getLine() : 1, + referenceContext, + problemSource + ); + IProblem[] seeAlso = buildSeeAlsoProblems(message.getExtraSourceLocations(), + problemSource, + usedBinarySourceFileName); + problem.setSeeAlsoProblems(seeAlso); + if (message.getDetails() != null) { + problem.setSupplementaryMessageInfo(message.getDetails()); + } + compiler.problemReporter.record(problem, problemSource, referenceContext); + return true; + } + + public boolean isIgnoring(Kind kind) { + return sink.isIgnoring(kind); + } + + private int getStartPos(ISourceLocation sLoc,CompilationResult result) { + int pos = 0; + if (sLoc == null) return 0; + int line = sLoc.getLine(); + if (sLoc instanceof EclipseSourceLocation) { + pos = ((EclipseSourceLocation)sLoc).getStartPos(); + } else { + if (line <= 1) return 0; + if (result != null) { + if ((result.lineSeparatorPositions != null) && + (result.lineSeparatorPositions.length >= (line-1))) { + pos = result.lineSeparatorPositions[line-2] + 1; + } + } + } + return pos; + } + + private int getEndPos(ISourceLocation sLoc,CompilationResult result) { + int pos = 0; + if (sLoc == null) return 0; + int line = sLoc.getLine(); + if (line <= 0) line = 1; + if (sLoc instanceof EclipseSourceLocation) { + pos = ((EclipseSourceLocation)sLoc).getEndPos(); + } else { + if (result != null) { + if ((result.lineSeparatorPositions != null) && + (result.lineSeparatorPositions.length >= line)) { + pos = result.lineSeparatorPositions[line -1] -1; + } + } + } + return pos; + } + + private ReferenceContext findReferenceContextFor(CompilationResult result) { + ReferenceContext context = null; + if (compiler.unitsToProcess == null) return null; + for (int i = 0; i < compiler.unitsToProcess.length; i++) { + if ((compiler.unitsToProcess[i] != null) && + (compiler.unitsToProcess[i].compilationResult == result)) { + context = compiler.unitsToProcess[i]; + break; + } + } + return context; + } + + private IProblem[] buildSeeAlsoProblems(List sourceLocations, + CompilationResult problemSource, + boolean usedBinarySourceFileName) { + int probLength = sourceLocations.size(); + if (usedBinarySourceFileName) probLength++; + IProblem[] ret = new IProblem[probLength]; + for (int i = 0; i < sourceLocations.size(); i++) { + ISourceLocation loc = (ISourceLocation) sourceLocations.get(i); + ret[i] = new DefaultProblem(loc.getSourceFile().getPath().toCharArray(), + "see also", + 0, + new String[] {}, + ProblemSeverities.Ignore, + getStartPos(loc,null), + getEndPos(loc,null), + loc.getLine()); + } + if (usedBinarySourceFileName) { + ret[ret.length -1] = new DefaultProblem(problemSource.fileName,"see also",0,new String[] {}, + ProblemSeverities.Ignore,0, + 0,0); + } + return ret; + } +} + diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceLocation.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceLocation.java index 43f2b8ee3..377f90474 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceLocation.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceLocation.java @@ -39,6 +39,18 @@ public class EclipseSourceLocation implements ISourceLocation { this.startPos = startPos; this.endPos = endPos; } + + public CompilationResult getCompilationResult() { + return result; + } + + public int getStartPos() { + return startPos; + } + + public int getEndPos() { + return endPos; + } public File getSourceFile() { if (null == file) { diff --git a/weaver/src/org/aspectj/weaver/ResolvedTypeX.java b/weaver/src/org/aspectj/weaver/ResolvedTypeX.java index 81327819e..15c86bdbb 100644 --- a/weaver/src/org/aspectj/weaver/ResolvedTypeX.java +++ b/weaver/src/org/aspectj/weaver/ResolvedTypeX.java @@ -577,7 +577,7 @@ public abstract class ResolvedTypeX extends TypeX { } public boolean isExposedToWeaver() { - return delegate.isExposedToWeaver(); //??? where does this belong + return (delegate == null) || delegate.isExposedToWeaver(); //??? where does this belong } public WeaverStateInfo getWeaverState() { @@ -652,7 +652,7 @@ public abstract class ResolvedTypeX extends TypeX { public static abstract class ConcreteName { //protected ISourceContext sourceContext; protected boolean exposedToWeaver; - ResolvedTypeX.Name resolvedTypeX; + protected ResolvedTypeX.Name resolvedTypeX; public ConcreteName(ResolvedTypeX.Name resolvedTypeX, boolean exposedToWeaver) { diff --git a/weaver/src/org/aspectj/weaver/World.java b/weaver/src/org/aspectj/weaver/World.java index 481778532..0d019fd1c 100644 --- a/weaver/src/org/aspectj/weaver/World.java +++ b/weaver/src/org/aspectj/weaver/World.java @@ -18,6 +18,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.WeakHashMap; import org.aspectj.asm.IHierarchy; import org.aspectj.bridge.IMessageHandler; @@ -32,7 +33,7 @@ public abstract class World { protected IMessageHandler messageHandler = IMessageHandler.SYSTEM_ERR; protected ICrossReferenceHandler xrefHandler = null; - protected Map typeMap = new HashMap(); // Signature to ResolvedType + protected TypeMap typeMap = new TypeMap(); // Signature to ResolvedType protected CrosscuttingMembersSet crosscuttingMembersSet = new CrosscuttingMembersSet(this); @@ -72,7 +73,7 @@ public abstract class World { public ResolvedTypeX resolve(TypeX ty, boolean allowMissing) { //System.out.println("resolve: " + ty + " world " + typeMap.keySet()); String signature = ty.getSignature(); - ResolvedTypeX ret = (ResolvedTypeX)typeMap.get(signature); + ResolvedTypeX ret = typeMap.get(signature); if (ret != null) return ret; if (ty.isArray()) { @@ -387,5 +388,75 @@ public abstract class World { return ret; } - + +// public void clearUnexposed() { +// List toRemove = new ArrayList(); +// for (Iterator iter = typeMap.keySet().iterator(); iter.hasNext();) { +// String sig = (String) iter.next(); +// ResolvedTypeX x = (ResolvedTypeX) typeMap.get(sig); +// if (!x.isExposedToWeaver() && (!x.isPrimitive())) toRemove.add(sig); +// } +// for (Iterator iter = toRemove.iterator(); iter.hasNext();) { +// typeMap.remove(iter.next()); +// } +// } +// +// // for testing... +// public void dumpTypeMap() { +// int exposed = 0; +// for (Iterator iter = typeMap.keySet().iterator(); iter.hasNext();) { +// String sig = (String) iter.next(); +// ResolvedTypeX x = (ResolvedTypeX) typeMap.get(sig); +// if (x.isExposedToWeaver()) exposed++; +// } +// System.out.println("type map contains " + typeMap.size() + " entries, " + exposed + " exposed to weaver"); +// } +// +// public void deepDumpTypeMap() { +// for (Iterator iter = typeMap.keySet().iterator(); iter.hasNext();) { +// String sig = (String) iter.next(); +// ResolvedTypeX x = (ResolvedTypeX) typeMap.get(sig); +// if (! (x instanceof ResolvedTypeX.Name)) { +// System.out.println(sig + " -> " + x.getClass().getName() + ", " + x.getClassName()); +// } else { +// ResolvedTypeX.ConcreteName cname = ((ResolvedTypeX.Name)x).getDelegate(); +// System.out.println(sig + " -> " + cname.getClass().getName() + ", " + cname.toString()); +// } +// } +// +// } + + // Map of types in the world, with soft links to expendable ones + protected static class TypeMap { + private Map tMap = new HashMap(); + private Map expendableMap = new WeakHashMap(); + + public ResolvedTypeX put(String key, ResolvedTypeX type) { + if (isExpendable(type)) { + return (ResolvedTypeX) expendableMap.put(key,type); + } else { + return (ResolvedTypeX) tMap.put(key,type); + } + } + + public ResolvedTypeX get(String key) { + ResolvedTypeX ret = (ResolvedTypeX) tMap.get(key); + if (ret == null) ret = (ResolvedTypeX) expendableMap.get(key); + return ret; + } + + public ResolvedTypeX remove(String key) { + ResolvedTypeX ret = (ResolvedTypeX) tMap.remove(key); + if (ret == null) ret = (ResolvedTypeX) expendableMap.remove(key); + return ret; + } + + private boolean isExpendable(ResolvedTypeX type) { + return ( + (type != null) && + (!type.isExposedToWeaver()) && + (!type.isPrimitive()) + ); + } + } } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java index 7c6ddb9fd..e0997573a 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java @@ -285,7 +285,7 @@ class BcelClassWeaver implements IClassWeaver { // ---- public boolean weave() { - + if (clazz.isWoven() && !clazz.isReweavable()) { world.showMessage(IMessage.ERROR, "class \'" + clazz.getType().getName() + "\' is already woven and has not been built with -Xreweavable", @@ -301,8 +301,7 @@ class BcelClassWeaver implements IClassWeaver { // we want to "touch" all aspects if (clazz.getType().isAspect()) isChanged = true; - - + // start by munging all typeMungers for (Iterator i = typeMungers.iterator(); i.hasNext(); ) { Object o = i.next(); @@ -327,13 +326,12 @@ class BcelClassWeaver implements IClassWeaver { if (addedSuperInitializersAsList == null) { throw new BCException("circularity in inter-types"); } - + // this will create a static initializer if there isn't one // this is in just as bad taste as NOPs LazyMethodGen staticInit = clazz.getStaticInitializer(); staticInit.getBody().insert(genInitInstructions(addedClassInitializers, true)); - // now go through each method, and match against each method. This // sets up each method's {@link LazyMethodGen#matchedShadows} field, // and it also possibly adds to {@link #initializationShadows}. @@ -351,6 +349,7 @@ class BcelClassWeaver implements IClassWeaver { } if (! isChanged) return false; + // now we weave all but the initialization shadows for (Iterator i = methodGens.iterator(); i.hasNext();) { LazyMethodGen mg = (LazyMethodGen)i.next(); @@ -785,72 +784,7 @@ class BcelClassWeaver implements IClassWeaver { List shadowAccumulator = new ArrayList(); // we want to match ajsynthetic constructors... if (mg.getName().equals("")) { - // XXX the enclosing join point is wrong for things before ignoreMe. - InstructionHandle superOrThisCall = findSuperOrThisCall(mg); - - // we don't walk bodies of things where it's a wrong constructor thingie - if (superOrThisCall == null) return false; - - enclosingShadow = BcelShadow.makeConstructorExecution(world, mg, superOrThisCall); - - // walk the body - boolean beforeSuperOrThisCall = true; - if (shouldWeaveBody(mg)) { - if (canMatchBodyShadows) { - for (InstructionHandle h = mg.getBody().getStart(); - h != null; - h = h.getNext()) { - if (h == superOrThisCall) { - beforeSuperOrThisCall = false; - continue; - } - match(mg, h, beforeSuperOrThisCall ? null : enclosingShadow, shadowAccumulator); - } - } - match(enclosingShadow, shadowAccumulator); - } - - // XXX we don't do pre-inits of interfaces - - // now add interface inits - if (superOrThisCall != null && ! isThisCall(superOrThisCall)) { - InstructionHandle curr = enclosingShadow.getRange().getStart(); - for (Iterator i = addedSuperInitializersAsList.iterator(); i.hasNext(); ) { - IfaceInitList l = (IfaceInitList) i.next(); - - Member ifaceInitSig = AjcMemberMaker.interfaceConstructor(l.onType); - - BcelShadow initShadow = - BcelShadow.makeIfaceInitialization(world, mg, ifaceInitSig); - - // insert code in place - InstructionList inits = genInitInstructions(l.list, false); - if (match(initShadow, shadowAccumulator) || !inits.isEmpty()) { - initShadow.initIfaceInitializer(curr); - initShadow.getRange().insert(inits, Range.OutsideBefore); - } - } - - // now we add our initialization code - InstructionList inits = genInitInstructions(addedThisInitializers, false); - enclosingShadow.getRange().insert(inits, Range.OutsideBefore); - } - - // actually, you only need to inline the self constructors that are - // in a particular group (partition the constructors into groups where members - // call or are called only by those in the group). Then only inline - // constructors - // in groups where at least one initialization jp matched. Future work. - boolean addedInitialization = - match( - BcelShadow.makeUnfinishedInitialization(world, mg), - initializationShadows); - addedInitialization |= - match( - BcelShadow.makeUnfinishedPreinitialization(world, mg), - initializationShadows); - mg.matchedShadows = shadowAccumulator; - return addedInitialization || !shadowAccumulator.isEmpty(); + return matchInit(mg, shadowAccumulator); } else if (!shouldWeaveBody(mg)) { //.isAjSynthetic()) { return false; } else { @@ -890,6 +824,76 @@ class BcelClassWeaver implements IClassWeaver { } } + private boolean matchInit(LazyMethodGen mg, List shadowAccumulator) { + BcelShadow enclosingShadow; + // XXX the enclosing join point is wrong for things before ignoreMe. + InstructionHandle superOrThisCall = findSuperOrThisCall(mg); + + // we don't walk bodies of things where it's a wrong constructor thingie + if (superOrThisCall == null) return false; + + enclosingShadow = BcelShadow.makeConstructorExecution(world, mg, superOrThisCall); + + // walk the body + boolean beforeSuperOrThisCall = true; + if (shouldWeaveBody(mg)) { + if (canMatchBodyShadows) { + for (InstructionHandle h = mg.getBody().getStart(); + h != null; + h = h.getNext()) { + if (h == superOrThisCall) { + beforeSuperOrThisCall = false; + continue; + } + match(mg, h, beforeSuperOrThisCall ? null : enclosingShadow, shadowAccumulator); + } + } + match(enclosingShadow, shadowAccumulator); + } + + // XXX we don't do pre-inits of interfaces + + // now add interface inits + if (superOrThisCall != null && ! isThisCall(superOrThisCall)) { + InstructionHandle curr = enclosingShadow.getRange().getStart(); + for (Iterator i = addedSuperInitializersAsList.iterator(); i.hasNext(); ) { + IfaceInitList l = (IfaceInitList) i.next(); + + Member ifaceInitSig = AjcMemberMaker.interfaceConstructor(l.onType); + + BcelShadow initShadow = + BcelShadow.makeIfaceInitialization(world, mg, ifaceInitSig); + + // insert code in place + InstructionList inits = genInitInstructions(l.list, false); + if (match(initShadow, shadowAccumulator) || !inits.isEmpty()) { + initShadow.initIfaceInitializer(curr); + initShadow.getRange().insert(inits, Range.OutsideBefore); + } + } + + // now we add our initialization code + InstructionList inits = genInitInstructions(addedThisInitializers, false); + enclosingShadow.getRange().insert(inits, Range.OutsideBefore); + } + + // actually, you only need to inline the self constructors that are + // in a particular group (partition the constructors into groups where members + // call or are called only by those in the group). Then only inline + // constructors + // in groups where at least one initialization jp matched. Future work. + boolean addedInitialization = + match( + BcelShadow.makeUnfinishedInitialization(world, mg), + initializationShadows); + addedInitialization |= + match( + BcelShadow.makeUnfinishedPreinitialization(world, mg), + initializationShadows); + mg.matchedShadows = shadowAccumulator; + return addedInitialization || !shadowAccumulator.isEmpty(); + } + private boolean shouldWeaveBody(LazyMethodGen mg) { if (mg.isAjSynthetic()) return mg.getName().equals(""); AjAttribute.EffectiveSignatureAttribute a = mg.getEffectiveSignature(); diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java b/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java index 1c8a44c0c..553e7c72d 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java @@ -216,7 +216,22 @@ public class BcelObjectType extends ResolvedTypeX.ConcreteName { isObject = (javaClass.getSuperclassNameIndex() == 0); unpackAspectAttributes(); } - + + public void finishedWith() { + // memory usage experiments.... +// this.interfaces = null; +// this.superClass = null; +// this.fields = null; +// this.methods = null; +// this.pointcuts = null; +// this.perClause = null; +// this.weaverState = null; +// this.lazyClassGen = null; + // this next line frees up memory, but need to understand incremental implications + // before leaving it in. +// getResolvedTypeX().setSourceContext(null); + } + public WeaverStateInfo getWeaverState() { return weaverState; } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java index 5d92584af..e71707cae 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java @@ -13,7 +13,7 @@ package org.aspectj.weaver.bcel; -import java.io.BufferedOutputStream; + import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileFilter; @@ -41,6 +41,8 @@ import org.aspectj.bridge.IProgressListener; import org.aspectj.util.FileUtil; import org.aspectj.weaver.ConcreteTypeMunger; import org.aspectj.weaver.CrosscuttingMembersSet; +import org.aspectj.weaver.IClassFileProvider; +import org.aspectj.weaver.IWeaveRequestor; import org.aspectj.weaver.IWeaver; import org.aspectj.weaver.NewParentTypeMunger; import org.aspectj.weaver.ResolvedTypeMunger; @@ -59,7 +61,6 @@ public class BcelWeaver implements IWeaver { private double progressPerClassFile; private boolean inReweavableMode = false; - private boolean compressReweavableAttributes = false; public BcelWeaver(BcelWorld world) { super(); @@ -72,7 +73,7 @@ public class BcelWeaver implements IWeaver { } // ---- fields - private Map sourceJavaClasses = new HashMap(); /* String -> UnwovenClassFile */ +// private Map sourceJavaClasses = new HashMap(); /* String -> UnwovenClassFile */ private List addedClasses = new ArrayList(); /* List */ private List deletedTypenames = new ArrayList(); /* List */ private Map resources = new HashMap(); /* String -> UnwovenClassFile */ @@ -139,13 +140,15 @@ public class BcelWeaver implements IWeaver { // The ANT copy task should be used to copy resources across. private final static boolean CopyResourcesFromInpathDirectoriesToOutput=false; + private Set alreadyConfirmedReweavableState; /** * Add any .class files in the directory to the outdir. Anything other than .class files in * the directory (or its subdirectories) are considered resources and are also copied. * */ - public void addDirectoryContents(File inFile,File outDir) throws IOException { + public List addDirectoryContents(File inFile,File outDir) throws IOException { + List addedClassFiles = new ArrayList(); // Get a list of all files (i.e. everything that isnt a directory) File[] files = FileUtil.listFiles(inFile,new FileFilter() { @@ -170,6 +173,7 @@ public class BcelWeaver implements IWeaver { if (filename.endsWith(".class")) { // System.err.println("BCELWeaver: processing class from input directory "+classFile); this.addClassFile(classFile); + addedClassFiles.add(classFile); } else { if (CopyResourcesFromInpathDirectoriesToOutput) { // System.err.println("BCELWeaver: processing resource from input directory "+filename); @@ -179,18 +183,20 @@ public class BcelWeaver implements IWeaver { fis.close(); } + return addedClassFiles; } /** Adds all class files in the jar */ - public void addJarFile(File inFile, File outDir, boolean canBeDirectory) throws IOException { + public List addJarFile(File inFile, File outDir, boolean canBeDirectory) throws IOException { // System.err.println("? addJarFile(" + inFile + ", " + outDir + ")"); + List addedClassFiles = new ArrayList(); needToReweaveWorld = true; // Is this a directory we are looking at? if (inFile.isDirectory() && canBeDirectory) { - addDirectoryContents(inFile,outDir); + addedClassFiles.addAll(addDirectoryContents(inFile,outDir)); } else { ZipInputStream inStream = new ZipInputStream(new FileInputStream(inFile)); //??? buffered @@ -205,6 +211,7 @@ public class BcelWeaver implements IWeaver { if (filename.endsWith(".class")) { this.addClassFile(classFile); + addedClassFiles.add(classFile); } else if (!entry.isDirectory()) { @@ -216,6 +223,8 @@ public class BcelWeaver implements IWeaver { } inStream.close(); } + + return addedClassFiles; } public void addResource(String name, File inPath, File outDir) throws IOException { @@ -232,21 +241,25 @@ public class BcelWeaver implements IWeaver { addResource(name,resourceFile); } } - + + public boolean needToReweaveWorld() { + return needToReweaveWorld; + } + /** Should be addOrReplace */ public void addClassFile(UnwovenClassFile classFile) { addedClasses.add(classFile); - if (null != sourceJavaClasses.put(classFile.getClassName(), classFile)) { -// throw new RuntimeException(classFile.getClassName()); - } +// if (null != sourceJavaClasses.put(classFile.getClassName(), classFile)) { +//// throw new RuntimeException(classFile.getClassName()); +// } world.addSourceObjectType(classFile.getJavaClass()); } public void deleteClassFile(String typename) { deletedTypenames.add(typename); - sourceJavaClasses.remove(typename); +// sourceJavaClasses.remove(typename); world.deleteSourceObjectType(TypeX.forName(typename)); } @@ -297,23 +310,23 @@ public class BcelWeaver implements IWeaver { }); } - public void dumpUnwoven(File file) throws IOException { - BufferedOutputStream os = FileUtil.makeOutputStream(file); - this.zipOutputStream = new ZipOutputStream(os); - dumpUnwoven(); - /* BUG 40943*/ - dumpResourcesToOutJar(); - zipOutputStream.close(); //this flushes and closes the acutal file - } - - - public void dumpUnwoven() throws IOException { - Collection filesToDump = new HashSet(sourceJavaClasses.values()); - for (Iterator i = filesToDump.iterator(); i.hasNext(); ) { - UnwovenClassFile classFile = (UnwovenClassFile)i.next(); - dumpUnchanged(classFile); - } - } +// public void dumpUnwoven(File file) throws IOException { +// BufferedOutputStream os = FileUtil.makeOutputStream(file); +// this.zipOutputStream = new ZipOutputStream(os); +// dumpUnwoven(); +// /* BUG 40943*/ +// dumpResourcesToOutJar(); +// zipOutputStream.close(); //this flushes and closes the acutal file +// } +// +// +// public void dumpUnwoven() throws IOException { +// Collection filesToDump = new HashSet(sourceJavaClasses.values()); +// for (Iterator i = filesToDump.iterator(); i.hasNext(); ) { +// UnwovenClassFile classFile = (UnwovenClassFile)i.next(); +// dumpUnchanged(classFile); +// } +// } public void dumpResourcesToOutPath() throws IOException { // System.err.println("? dumpResourcesToOutPath() resources=" + resources.keySet()); @@ -322,6 +335,7 @@ public class BcelWeaver implements IWeaver { UnwovenClassFile res = (UnwovenClassFile)resources.get(i.next()); dumpUnchanged(res); } + //resources = new HashMap(); } /* BUG #40943 */ @@ -333,127 +347,248 @@ public class BcelWeaver implements IWeaver { UnwovenClassFile res = (UnwovenClassFile)resources.get(name); writeZipEntry(name,res.getBytes()); } + //resources = new HashMap(); + } + + // halfway house for when the jar is managed outside of the weaver, but the resources + // to be copied are known in the weaver. + public void dumpResourcesToOutJar(ZipOutputStream zos) throws IOException { + this.zipOutputStream = zos; + dumpResourcesToOutJar(); } // ---- weaving + // Used by some test cases... public Collection weave(File file) throws IOException { OutputStream os = FileUtil.makeOutputStream(file); this.zipOutputStream = new ZipOutputStream(os); - Collection c = weave(); + prepareForWeave(); + Collection c = weave( new IClassFileProvider() { + + public Iterator getClassFileIterator() { + return addedClasses.iterator(); + } + + public IWeaveRequestor getRequestor() { + return new IWeaveRequestor() { + public void acceptResult(UnwovenClassFile result) {} + public void processingReweavableState() {} + public void addingTypeMungers() {} + public void weavingAspects() {} + public void weavingClasses() {} + public void weaveCompleted() {} + }; + } + }); /* BUG 40943*/ dumpResourcesToOutJar(); zipOutputStream.close(); //this flushes and closes the acutal file return c; } - public Collection weave() throws IOException { - prepareForWeave(); - Collection filesToWeave; - - if (needToReweaveWorld) { - filesToWeave = sourceJavaClasses.values(); - } else { - filesToWeave = addedClasses; - } - +// public Collection weave() throws IOException { +// prepareForWeave(); +// Collection filesToWeave; +// +// if (needToReweaveWorld) { +// filesToWeave = sourceJavaClasses.values(); +// } else { +// filesToWeave = addedClasses; +// } +// +// Collection wovenClassNames = new ArrayList(); +// world.showMessage(IMessage.INFO, "might need to weave " + filesToWeave + +// "(world=" + needToReweaveWorld + ")", null, null); +// +// +// //System.err.println("typeMungers: " + typeMungerList); +// +// prepareToProcessReweavableState(); +// // clear all state from files we'll be reweaving +// for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { +// UnwovenClassFile classFile = (UnwovenClassFile)i.next(); +// String className = classFile.getClassName(); +// BcelObjectType classType = getClassType(className); +// processReweavableStateIfPresent(className, classType); +// } +// +// +// +// //XXX this isn't quite the right place for this... +// for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { +// UnwovenClassFile classFile = (UnwovenClassFile)i.next(); +// String className = classFile.getClassName(); +// addTypeMungers(className); +// } +// +// // first weave into aspects +// for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { +// UnwovenClassFile classFile = (UnwovenClassFile)i.next(); +// String className = classFile.getClassName(); +// BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className)); +// if (classType.isAspect()) { +// weave(classFile, classType); +// wovenClassNames.add(className); +// } +// } +// +// // then weave into non-aspects +// for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { +// UnwovenClassFile classFile = (UnwovenClassFile)i.next(); +// String className = classFile.getClassName(); +// BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className)); +// if (! classType.isAspect()) { +// weave(classFile, classType); +// wovenClassNames.add(className); +// } +// } +// +// if (zipOutputStream != null && !needToReweaveWorld) { +// Collection filesToDump = new HashSet(sourceJavaClasses.values()); +// filesToDump.removeAll(filesToWeave); +// for (Iterator i = filesToDump.iterator(); i.hasNext(); ) { +// UnwovenClassFile classFile = (UnwovenClassFile)i.next(); +// dumpUnchanged(classFile); +// } +// } +// +// addedClasses = new ArrayList(); +// deletedTypenames = new ArrayList(); +// +// return wovenClassNames; +// } + + // variation of "weave" that sources class files from an external source. + public Collection weave(IClassFileProvider input) throws IOException { Collection wovenClassNames = new ArrayList(); - world.showMessage(IMessage.INFO, "might need to weave " + filesToWeave + - "(world=" + needToReweaveWorld + ")", null, null); - - - //System.err.println("typeMungers: " + typeMungerList); - + IWeaveRequestor requestor = input.getRequestor(); - if (inReweavableMode) - world.showMessage(IMessage.INFO, "weaver operating in reweavable mode. Need to verify any required types exist.", null, null); - - - Set alreadyConfirmedOK = new HashSet(); + requestor.processingReweavableState(); + prepareToProcessReweavableState(); // clear all state from files we'll be reweaving - for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { - UnwovenClassFile classFile = (UnwovenClassFile)i.next(); - String className = classFile.getClassName(); - BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className)); + for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) { + UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + String className = classFile.getClassName(); + BcelObjectType classType = getClassType(className); + processReweavableStateIfPresent(className, classType); + } + + requestor.addingTypeMungers(); + //XXX this isn't quite the right place for this... + for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) { + UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + String className = classFile.getClassName(); + addTypeMungers(className); + } - - // If the class is marked reweavable, check any aspects around when it was built are in this world - WeaverStateInfo wsi = classType.getWeaverState(); - if (wsi!=null && wsi.isReweavable()) { // Check all necessary types are around! - world.showMessage(IMessage.INFO,"processing reweavable type "+className+": "+classType.getSourceLocation().getSourceFile(),null,null); - Set aspectsPreviouslyInWorld = wsi.getAspectsAffectingType(); - if (aspectsPreviouslyInWorld!=null) { - for (Iterator iter = aspectsPreviouslyInWorld.iterator(); iter.hasNext();) { - String requiredTypeName = (String) iter.next(); - if (!alreadyConfirmedOK.contains(requiredTypeName)) { - ResolvedTypeX rtx = world.resolve(TypeX.forName(requiredTypeName),true); - boolean exists = rtx!=ResolvedTypeX.MISSING; - if (!exists) { - world.showMessage(IMessage.ERROR, "type " + requiredTypeName + - " is needed by reweavable type " + className, - classType.getSourceLocation(), null); - } else { - if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) - world.showMessage(IMessage.INFO,"successfully verified type "+requiredTypeName+ - " exists. Originates from "+rtx.getSourceLocation().getSourceFile(),null,null); - alreadyConfirmedOK.add(requiredTypeName); - } - } - } - } - classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData())); - } else { - classType.resetState(); - } - } - - - - //XXX this isn't quite the right place for this... - for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { - UnwovenClassFile classFile = (UnwovenClassFile)i.next(); - String className = classFile.getClassName(); - ResolvedTypeX onType = world.resolve(className); - weave(onType); - } - + requestor.weavingAspects(); // first weave into aspects - for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { - UnwovenClassFile classFile = (UnwovenClassFile)i.next(); - String className = classFile.getClassName(); - BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className)); - if (classType.isAspect()) { - weave(classFile, classType); - wovenClassNames.add(className); - } - } + for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) { + UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + String className = classFile.getClassName(); + BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className)); + if (classType.isAspect()) { + weaveAndNotify(classFile, classType,requestor); + wovenClassNames.add(className); + } + } + requestor.weavingClasses(); // then weave into non-aspects - for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { - UnwovenClassFile classFile = (UnwovenClassFile)i.next(); - String className = classFile.getClassName(); - BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className)); - if (! classType.isAspect()) { - weave(classFile, classType); - wovenClassNames.add(className); - } - } - - if (zipOutputStream != null && !needToReweaveWorld) { - Collection filesToDump = new HashSet(sourceJavaClasses.values()); - filesToDump.removeAll(filesToWeave); - for (Iterator i = filesToDump.iterator(); i.hasNext(); ) { - UnwovenClassFile classFile = (UnwovenClassFile)i.next(); - dumpUnchanged(classFile); - } - } - - addedClasses = new ArrayList(); - deletedTypenames = new ArrayList(); + for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) { + UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + String className = classFile.getClassName(); + BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className)); + if (! classType.isAspect()) { + weaveAndNotify(classFile, classType, requestor); + wovenClassNames.add(className); + } + } - return wovenClassNames; + addedClasses = new ArrayList(); + deletedTypenames = new ArrayList(); + requestor.weaveCompleted(); + + return wovenClassNames; + } + + public void prepareToProcessReweavableState() { + if (inReweavableMode) + world.showMessage(IMessage.INFO, "weaver operating in reweavable mode. Need to verify any required types exist.", null, null); + + alreadyConfirmedReweavableState = new HashSet(); + } + + public void processReweavableStateIfPresent(String className, BcelObjectType classType) { + // If the class is marked reweavable, check any aspects around when it was built are in this world + WeaverStateInfo wsi = classType.getWeaverState(); + if (wsi!=null && wsi.isReweavable()) { // Check all necessary types are around! + world.showMessage(IMessage.INFO,"processing reweavable type "+className+": "+classType.getSourceLocation().getSourceFile(),null,null); + Set aspectsPreviouslyInWorld = wsi.getAspectsAffectingType(); + if (aspectsPreviouslyInWorld!=null) { + for (Iterator iter = aspectsPreviouslyInWorld.iterator(); iter.hasNext();) { + String requiredTypeName = (String) iter.next(); + if (!alreadyConfirmedReweavableState.contains(requiredTypeName)) { + ResolvedTypeX rtx = world.resolve(TypeX.forName(requiredTypeName),true); + boolean exists = rtx!=ResolvedTypeX.MISSING; + if (!exists) { + world.showMessage(IMessage.ERROR, "type " + requiredTypeName + + " is needed by reweavable type " + className, + classType.getSourceLocation(), null); + } else { + if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) + world.showMessage(IMessage.INFO,"successfully verified type "+requiredTypeName+ + " exists. Originates from "+rtx.getSourceLocation().getSourceFile(),null,null); + alreadyConfirmedReweavableState.add(requiredTypeName); + } + } + } + } + classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData())); + } else { + classType.resetState(); + } + } + + private void weaveAndNotify(UnwovenClassFile classFile, BcelObjectType classType, + IWeaveRequestor requestor) throws IOException { + LazyClassGen clazz = weaveWithoutDump(classFile,classType); + classType.finishedWith(); + //clazz is null if the classfile was unchanged by weaving... + if (clazz != null) { + UnwovenClassFile[] newClasses = getClassFilesFor(clazz); + for (int i = 0; i < newClasses.length; i++) { + requestor.acceptResult(newClasses[i]); + } + } else { + requestor.acceptResult(classFile); + } + } + + // helper method + public BcelObjectType getClassType(String forClass) { + return BcelWorld.getBcelObjectType(world.resolve(forClass)); + } + + + public void addTypeMungers(String typeName) { + weave(world.resolve(typeName)); } + public UnwovenClassFile[] getClassFilesFor(LazyClassGen clazz) { + List childClasses = clazz.getChildClasses(world); + UnwovenClassFile[] ret = new UnwovenClassFile[1 + childClasses.size()]; + ret[0] = new UnwovenClassFile(clazz.getFileName(),clazz.getJavaClass(world).getBytes()); + int index = 1; + for (Iterator iter = childClasses.iterator(); iter.hasNext();) { + UnwovenClassFile.ChildClass element = (UnwovenClassFile.ChildClass) iter.next(); + UnwovenClassFile childClass = new UnwovenClassFile(clazz.getFileName() + "$" + element.name, element.bytes); + ret[index++] = childClass; + } + return ret; + } + public void weave(ResolvedTypeX onType) { onType.clearInterTypeMungers(); @@ -622,9 +757,11 @@ public class BcelWeaver implements IWeaver { public void setReweavableMode(boolean mode,boolean compress) { inReweavableMode = mode; - compressReweavableAttributes = compress; WeaverStateInfo.setReweavableModeDefaults(mode,compress); BcelClassWeaver.setReweavableMode(mode,compress); } + public boolean isReweavable() { + return inReweavableMode; + } } diff --git a/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFileWithThirdPartyManagedBytecode.java b/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFileWithThirdPartyManagedBytecode.java new file mode 100644 index 000000000..d7e6c96ac --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFileWithThirdPartyManagedBytecode.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.aspectj.weaver.bcel; + +/** + * @author colyer + * This subclass of UnwovenClassFile allows a third-party to + * manage the actual bytes that comprise the class. This means + * the third party can return a reference to an existing array, + * or create the bytes on demand, or apply any other strategy + * that makes sense. By refering to bytes held elsewhere, the + * goal is to reduce the overall memory consumption by not holding + * a copy. + */ +public class UnwovenClassFileWithThirdPartyManagedBytecode + extends UnwovenClassFile { + + IByteCodeProvider provider; + + public interface IByteCodeProvider { + byte[] getBytes(); + } + + public UnwovenClassFileWithThirdPartyManagedBytecode(String filename, + IByteCodeProvider provider) { + super(filename,null); + this.provider = provider; + } + + public byte[] getBytes() { + return provider.getBytes(); + } +}