From e75d0c16fe2ff676bbb85ae3397f45200959a38a Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Sun, 25 Nov 2012 19:42:56 +0100 Subject: [PATCH] generalized instrumentation --- .../jps/incremental/IncProjectBuilder.java | 8 +- .../jps/incremental/JavaBuilderService.java | 2 +- .../jps/incremental/ModuleLevelBuilder.java | 5 +- .../BaseInstrumentingBuilder.java | 160 ++++++++++++++++++ .../NotNullInstrumentingBuilder.java | 78 +++++++++ .../jps/incremental/java/JavaBuilder.java | 2 +- .../java/NotNullInstrumentingBuilder.java | 147 ---------------- .../jps/incremental/groovy/GroovyBuilder.java | 2 +- .../compiler/FormsInstrumenter.java | 66 ++------ 9 files changed, 263 insertions(+), 207 deletions(-) create mode 100644 jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/BaseInstrumentingBuilder.java create mode 100644 jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/NotNullInstrumentingBuilder.java delete mode 100644 jps/jps-builders/src/org/jetbrains/jps/incremental/java/NotNullInstrumentingBuilder.java diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 09299ee73205..de4640983d81 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -772,6 +772,12 @@ public class IncProjectBuilder { // return true if changed something, false otherwise private boolean runModuleLevelBuilders(final CompileContext context, final ModuleChunk chunk) throws ProjectBuildException, IOException { + for (BuilderCategory category : BuilderCategory.values()) { + for (ModuleLevelBuilder builder : myBuilderRegistry.getBuilders(category)) { + builder.chunkBuildStarted(context, chunk); + } + } + boolean doneSomething = false; boolean rebuildFromScratchRequested = false; float stageCount = myTotalModuleLevelBuilderCount; @@ -878,7 +884,7 @@ public class IncProjectBuilder { outputConsumer.clear(); for (BuilderCategory category : BuilderCategory.values()) { for (ModuleLevelBuilder builder : myBuilderRegistry.getBuilders(category)) { - builder.cleanupChunkResources(context); + builder.chunkBuildFinished(context, chunk); } } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/JavaBuilderService.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/JavaBuilderService.java index e07c7372dcda..b9908a505338 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/JavaBuilderService.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/JavaBuilderService.java @@ -4,8 +4,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.builders.BuildTargetType; import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType; import org.jetbrains.jps.builders.java.ResourcesTargetType; +import org.jetbrains.jps.incremental.instrumentation.NotNullInstrumentingBuilder; import org.jetbrains.jps.incremental.java.JavaBuilder; -import org.jetbrains.jps.incremental.java.NotNullInstrumentingBuilder; import org.jetbrains.jps.incremental.resources.ResourcesBuilder; import org.jetbrains.jps.service.SharedThreadPool; diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleLevelBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleLevelBuilder.java index 9ba61c0993cf..bbc39426e3d9 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleLevelBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleLevelBuilder.java @@ -57,6 +57,9 @@ public abstract class ModuleLevelBuilder extends Builder { return myCategory; } - public void cleanupChunkResources(CompileContext context) { + public void chunkBuildStarted(CompileContext context, ModuleChunk chunk) { + } + + public void chunkBuildFinished(CompileContext context, ModuleChunk chunk) { } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/BaseInstrumentingBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/BaseInstrumentingBuilder.java new file mode 100644 index 000000000000..a41bba5ecc0e --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/BaseInstrumentingBuilder.java @@ -0,0 +1,160 @@ +package org.jetbrains.jps.incremental.instrumentation; + +import com.intellij.compiler.instrumentation.InstrumentationClassFinder; +import com.intellij.compiler.instrumentation.InstrumenterClassWriter; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.asm4.ClassReader; +import org.jetbrains.asm4.ClassVisitor; +import org.jetbrains.asm4.ClassWriter; +import org.jetbrains.asm4.Opcodes; +import org.jetbrains.jps.ModuleChunk; +import org.jetbrains.jps.ProjectPaths; +import org.jetbrains.jps.builders.DirtyFilesHolder; +import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor; +import org.jetbrains.jps.incremental.*; +import org.jetbrains.jps.incremental.messages.ProgressMessage; +import org.jetbrains.jps.javac.BinaryContent; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; + +/** + * @author Eugene Zhuravlev + * Date: 11/25/12 + */ +public abstract class BaseInstrumentingBuilder extends ModuleLevelBuilder{ + private static final Key CLASS_FINDER = Key.create("_cached_instrumentation_class_finder_"); + + public BaseInstrumentingBuilder() { + super(BuilderCategory.CLASS_INSTRUMENTER); + } + + @Override + public void chunkBuildStarted(CompileContext context, ModuleChunk chunk) { + } + + @Override + public void chunkBuildFinished(CompileContext context, ModuleChunk chunk) { + final InstrumentationClassFinder finder = CLASS_FINDER.get(context); + CLASS_FINDER.set(context, null); + if (finder != null) { + finder.releaseResources(); + } + } + + @Override + public final ExitCode build(CompileContext context, ModuleChunk chunk, DirtyFilesHolder dirtyFilesHolder, OutputConsumer outputConsumer) throws ProjectBuildException, IOException { + ExitCode exitCode = ExitCode.NOTHING_DONE; + if (outputConsumer.getCompiledClasses().isEmpty() || !isEnabled(context, chunk)) { + return exitCode; + } + + InstrumentationClassFinder finder = null; + final String progress = getProgressMessage(); + final boolean shouldShowProgress = !StringUtil.isEmptyOrSpaces(progress); + if (shouldShowProgress) { + context.processMessage(new ProgressMessage(progress + " [" + chunk.getName() + "]")); + } + + try { + for (CompiledClass compiledClass : outputConsumer.getCompiledClasses().values()) { + final BinaryContent originalContent = compiledClass.getContent(); + final ClassReader reader = new ClassReader(originalContent.getBuffer(), originalContent.getOffset(), originalContent.getLength()); + final int version = getClassFileVersion(reader); + if (!canInstrument(compiledClass, version)) { + continue; + } + + if (finder == null) { // lazy init for this particular builder + finder = CLASS_FINDER.get(context); // try using shared finder + if (finder == null) { + final ProjectPaths paths = context.getProjectPaths(); + final Collection platformCp = paths.getPlatformCompilationClasspath(chunk, false); + + final Collection classpath = new ArrayList(); + classpath.addAll(paths.getCompilationClasspath(chunk, false)); + classpath.addAll(ProjectPaths.getSourceRootsWithDependents(chunk).keySet()); + + finder = createInstrumentationClassFinder(platformCp, classpath, outputConsumer); + CLASS_FINDER.set(context, finder); + } + } + + final ClassWriter writer = new InstrumenterClassWriter(getAsmClassWriterFlags(version), finder); + final BinaryContent instrumented = instrument(context, compiledClass, reader, writer, finder); + if (instrumented != null) { + compiledClass.setContent(instrumented); + exitCode = ExitCode.OK; + } + } + } + finally { + if (shouldShowProgress) { + context.processMessage(new ProgressMessage("")); // cleanup progress + } + } + return exitCode; + } + + protected abstract boolean isEnabled(CompileContext context, ModuleChunk chunk); + + protected abstract boolean canInstrument(CompiledClass compiledClass, int classFileVersion); + + @Nullable + protected abstract BinaryContent instrument(CompileContext context, + CompiledClass compiled, + ClassReader reader, + ClassWriter writer, + InstrumentationClassFinder finder); + + protected abstract String getProgressMessage(); + // utility methods + + public static InstrumentationClassFinder createInstrumentationClassFinder(Collection platformCp, Collection cp, final OutputConsumer outputConsumer) throws MalformedURLException { + final URL[] platformUrls = new URL[platformCp.size()]; + int index = 0; + for (File file : platformCp) { + platformUrls[index++] = file.toURI().toURL(); + } + + final URL[] urls = new URL[cp.size()]; + index = 0; + for (File file : cp) { + urls[index++] = file.toURI().toURL(); + } + + return new InstrumentationClassFinder(platformUrls, urls) { + protected InputStream lookupClassBeforeClasspath(String internalClassName) { + final BinaryContent content = outputConsumer.lookupClassBytes(internalClassName.replace("/", ".")); + if (content != null) { + return new ByteArrayInputStream(content.getBuffer(), content.getOffset(), content.getLength()); + } + return null; + } + }; + } + + public static int getAsmClassWriterFlags(int version) { + return version >= Opcodes.V1_6 && version != Opcodes.V1_1 ? ClassWriter.COMPUTE_FRAMES : ClassWriter.COMPUTE_MAXS; + } + + public static int getClassFileVersion(ClassReader reader) { + final Ref result = new Ref(0); + reader.accept(new ClassVisitor(Opcodes.ASM4) { + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + result.set(version); + } + }, 0); + return result.get(); + } + +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/NotNullInstrumentingBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/NotNullInstrumentingBuilder.java new file mode 100644 index 000000000000..caef353ccde9 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/NotNullInstrumentingBuilder.java @@ -0,0 +1,78 @@ +package org.jetbrains.jps.incremental.instrumentation; + +import com.intellij.compiler.instrumentation.InstrumentationClassFinder; +import com.intellij.compiler.notNullVerification.NotNullVerifyingInstrumenter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.asm4.ClassReader; +import org.jetbrains.asm4.ClassWriter; +import org.jetbrains.asm4.Opcodes; +import org.jetbrains.jps.ModuleChunk; +import org.jetbrains.jps.cmdline.ProjectDescriptor; +import org.jetbrains.jps.incremental.CompileContext; +import org.jetbrains.jps.incremental.CompiledClass; +import org.jetbrains.jps.incremental.messages.BuildMessage; +import org.jetbrains.jps.incremental.messages.CompilerMessage; +import org.jetbrains.jps.javac.BinaryContent; +import org.jetbrains.jps.model.java.JpsJavaExtensionService; + +import java.io.File; + +/** + * @author Eugene Zhuravlev + * Date: 11/21/12 + */ +public class NotNullInstrumentingBuilder extends BaseInstrumentingBuilder{ + + public NotNullInstrumentingBuilder() { + } + + @NotNull + @Override + public String getPresentableName() { + return "NotNull instrumentation"; + } + + @Override + protected String getProgressMessage() { + return "Adding @NotNull assertions..."; + } + + @Override + protected boolean isEnabled(CompileContext context, ModuleChunk chunk) { + final ProjectDescriptor pd = context.getProjectDescriptor(); + return JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(pd.getProject()).isAddNotNullAssertions(); + } + + @Override + protected boolean canInstrument(CompiledClass compiledClass, int classFileVersion) { + return classFileVersion >= Opcodes.V1_5; + } + + // todo: probably instrument other NotNull-like annotations defined in project settings? + @Override + @Nullable + protected BinaryContent instrument(CompileContext context, + CompiledClass compiledClass, + ClassReader reader, + ClassWriter writer, + InstrumentationClassFinder finder) { + try { + final NotNullVerifyingInstrumenter instrumenter = new NotNullVerifyingInstrumenter(writer); + reader.accept(instrumenter, 0); + if (instrumenter.isModification()) { + return new BinaryContent(writer.toByteArray()); + } + } + catch (Throwable e) { + final StringBuilder msg = new StringBuilder(); + msg.append("@NotNull instrumentation failed "); + final File sourceFile = compiledClass.getSourceFile(); + msg.append(" for ").append(sourceFile.getName()); + msg.append(": ").append(e.getMessage()); + context.processMessage(new CompilerMessage(getPresentableName(), BuildMessage.Kind.ERROR, msg.toString(), sourceFile.getPath())); + } + return null; + } + +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index 7dd9f023d069..40c5c958a766 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -681,7 +681,7 @@ public class JavaBuilder extends ModuleLevelBuilder { } @Override - public void cleanupChunkResources(CompileContext context) { + public void chunkBuildFinished(CompileContext context, ModuleChunk chunk) { JavaBuilderUtil.cleanupChunkResources(context); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/NotNullInstrumentingBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/NotNullInstrumentingBuilder.java deleted file mode 100644 index 58fe5b8fdfb7..000000000000 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/NotNullInstrumentingBuilder.java +++ /dev/null @@ -1,147 +0,0 @@ -package org.jetbrains.jps.incremental.java; - -import com.intellij.compiler.instrumentation.InstrumentationClassFinder; -import com.intellij.compiler.instrumentation.InstrumenterClassWriter; -import com.intellij.compiler.notNullVerification.NotNullVerifyingInstrumenter; -import com.intellij.openapi.util.Ref; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.asm4.ClassReader; -import org.jetbrains.asm4.ClassVisitor; -import org.jetbrains.asm4.ClassWriter; -import org.jetbrains.asm4.Opcodes; -import org.jetbrains.jps.ModuleChunk; -import org.jetbrains.jps.ProjectPaths; -import org.jetbrains.jps.builders.DirtyFilesHolder; -import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor; -import org.jetbrains.jps.cmdline.ProjectDescriptor; -import org.jetbrains.jps.incremental.*; -import org.jetbrains.jps.incremental.messages.BuildMessage; -import org.jetbrains.jps.incremental.messages.CompilerMessage; -import org.jetbrains.jps.incremental.messages.ProgressMessage; -import org.jetbrains.jps.javac.BinaryContent; -import org.jetbrains.jps.model.java.JpsJavaExtensionService; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -/** - * @author Eugene Zhuravlev - * Date: 11/21/12 - */ -public class NotNullInstrumentingBuilder extends ModuleLevelBuilder{ - - public NotNullInstrumentingBuilder() { - super(BuilderCategory.CLASS_INSTRUMENTER); - } - - @NotNull - @Override - public String getPresentableName() { - return "NotNull instrumentation"; - } - - @Override - public ExitCode build(CompileContext context, - ModuleChunk chunk, - DirtyFilesHolder dirtyFilesHolder, - OutputConsumer outputConsumer) throws ProjectBuildException, IOException { - ExitCode exitCode = ExitCode.NOTHING_DONE; - - final ProjectDescriptor pd = context.getProjectDescriptor(); - final boolean addNotNullAssertions = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(pd.getProject()).isAddNotNullAssertions(); - if (addNotNullAssertions && !outputConsumer.getCompiledClasses().isEmpty()) { - final ProjectPaths paths = context.getProjectPaths(); - final Collection classpath = paths.getCompilationClasspath(chunk, false); - final Collection platformCp = paths.getPlatformCompilationClasspath(chunk, false); - final InstrumentationClassFinder finder = createInstrumentationClassFinder(platformCp, classpath, outputConsumer); - try { - try { - context.processMessage(new ProgressMessage("Adding @NotNull assertions... [" + chunk.getName() + "]")); - exitCode = instrumentNotNull(context, outputConsumer, finder); - } - finally { - context.processMessage(new ProgressMessage("Finished adding @NotNull assertions [" + chunk.getName() + "]")); - } - } - finally { - finder.releaseResources(); - } - } - return exitCode; - } - - // todo: probably instrument other NotNull-like annotations defined in project settings? - private ExitCode instrumentNotNull(CompileContext context, OutputConsumer outputConsumer, final InstrumentationClassFinder finder) { - boolean doneSomething = false; - for (final CompiledClass compiledClass : outputConsumer.getCompiledClasses().values()) { - final BinaryContent originalContent = compiledClass.getContent(); - final ClassReader reader = new ClassReader(originalContent.getBuffer(), originalContent.getOffset(), originalContent.getLength()); - final int version = getClassFileVersion(reader); - if (version >= Opcodes.V1_5) { - final ClassWriter writer = new InstrumenterClassWriter(getAsmClassWriterFlags(version), finder); - try { - final NotNullVerifyingInstrumenter instrumenter = new NotNullVerifyingInstrumenter(writer); - reader.accept(instrumenter, 0); - if (instrumenter.isModification()) { - compiledClass.setContent(new BinaryContent(writer.toByteArray())); - doneSomething = true; - } - } - catch (Throwable e) { - doneSomething = true; - final StringBuilder msg = new StringBuilder(); - msg.append("@NotNull instrumentation failed "); - final File sourceFile = compiledClass.getSourceFile(); - msg.append(" for ").append(sourceFile.getName()); - msg.append(": ").append(e.getMessage()); - context.processMessage(new CompilerMessage(getPresentableName(), BuildMessage.Kind.ERROR, msg.toString(), sourceFile.getPath())); - } - } - } - return doneSomething? ExitCode.OK : ExitCode.NOTHING_DONE; - } - - private static InstrumentationClassFinder createInstrumentationClassFinder(Collection platformCp, Collection classpath, final OutputConsumer outputConsumer) throws MalformedURLException { - final URL[] platformUrls = new URL[platformCp.size()]; - int index = 0; - for (File file : platformCp) { - platformUrls[index++] = file.toURI().toURL(); - } - - final List urls = new ArrayList(classpath.size()); - for (File file : classpath) { - urls.add(file.toURI().toURL()); - } - - return new InstrumentationClassFinder(platformUrls, urls.toArray(new URL[urls.size()])) { - protected InputStream lookupClassBeforeClasspath(String internalClassName) { - final BinaryContent content = outputConsumer.lookupClassBytes(internalClassName.replace("/", ".")); - if (content != null) { - return new ByteArrayInputStream(content.getBuffer(), content.getOffset(), content.getLength()); - } - return null; - } - }; - } - - private static int getClassFileVersion(ClassReader reader) { - final Ref result = new Ref(0); - reader.accept(new ClassVisitor(Opcodes.ASM4) { - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - result.set(version); - } - }, 0); - return result.get(); - } - - private static int getAsmClassWriterFlags(int version) { - return version >= Opcodes.V1_6 && version != Opcodes.V1_1 ? ClassWriter.COMPUTE_FRAMES : ClassWriter.COMPUTE_MAXS; - } -} diff --git a/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java b/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java index 89762cd63df1..99060e81c62a 100644 --- a/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java +++ b/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java @@ -252,7 +252,7 @@ public class GroovyBuilder extends ModuleLevelBuilder { } @Override - public void cleanupChunkResources(CompileContext context) { + public void chunkBuildFinished(CompileContext context, ModuleChunk chunk) { JavaBuilderUtil.cleanupChunkResources(context); STUB_TO_SRC.set(context, null); } diff --git a/plugins/ui-designer/jps-plugin/src/org/jetbrains/jps/uiDesigner/compiler/FormsInstrumenter.java b/plugins/ui-designer/jps-plugin/src/org/jetbrains/jps/uiDesigner/compiler/FormsInstrumenter.java index bab7dfc0e596..f68bc27ebf28 100644 --- a/plugins/ui-designer/jps-plugin/src/org/jetbrains/jps/uiDesigner/compiler/FormsInstrumenter.java +++ b/plugins/ui-designer/jps-plugin/src/org/jetbrains/jps/uiDesigner/compiler/FormsInstrumenter.java @@ -18,7 +18,6 @@ package org.jetbrains.jps.uiDesigner.compiler; import com.intellij.compiler.instrumentation.InstrumentationClassFinder; import com.intellij.compiler.instrumentation.InstrumenterClassWriter; import com.intellij.openapi.application.PathManager; -import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.uiDesigner.compiler.*; import com.intellij.uiDesigner.compiler.Utils; @@ -28,9 +27,6 @@ import com.intellij.uiDesigner.lw.LwRootContainer; import gnu.trove.THashSet; import org.jetbrains.annotations.Nullable; import org.jetbrains.asm4.ClassReader; -import org.jetbrains.asm4.ClassVisitor; -import org.jetbrains.asm4.ClassWriter; -import org.jetbrains.asm4.Opcodes; import org.jetbrains.jps.ModuleChunk; import org.jetbrains.jps.ProjectPaths; import org.jetbrains.jps.builders.DirtyFilesHolder; @@ -38,6 +34,7 @@ import org.jetbrains.jps.builders.FileProcessor; import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor; import org.jetbrains.jps.builders.logging.ProjectBuilderLogger; import org.jetbrains.jps.incremental.*; +import org.jetbrains.jps.incremental.instrumentation.BaseInstrumentingBuilder; import org.jetbrains.jps.incremental.messages.BuildMessage; import org.jetbrains.jps.incremental.messages.CompilerMessage; import org.jetbrains.jps.incremental.messages.ProgressMessage; @@ -48,8 +45,6 @@ import org.jetbrains.jps.uiDesigner.model.JpsUiDesignerConfiguration; import org.jetbrains.jps.uiDesigner.model.JpsUiDesignerExtensionService; import java.io.*; -import java.net.MalformedURLException; -import java.net.URL; import java.util.*; /** @@ -93,10 +88,16 @@ public class FormsInstrumenter extends FormsBuilder { try { final ProjectPaths paths = context.getProjectPaths(); - final Collection classpath = paths.getCompilationClasspath(chunk, false); final Collection platformCp = paths.getPlatformCompilationClasspath(chunk, false); + + final List classpath = new ArrayList(); + classpath.addAll(paths.getCompilationClasspath(chunk, false)); + classpath.add(getResourcePath(GridConstraints.class)); // forms_rt.jar final Map chunkSourcePath = ProjectPaths.getSourceRootsWithDependents(chunk); - final InstrumentationClassFinder finder = createInstrumentationClassFinder(platformCp, classpath, chunkSourcePath, outputConsumer); + classpath.addAll(chunkSourcePath.keySet()); // sourcepath for loading forms resources + + final InstrumentationClassFinder finder = + BaseInstrumentingBuilder.createInstrumentationClassFinder(platformCp, classpath, outputConsumer); try { instrumentForms(context, chunk, chunkSourcePath, finder, forms, outputConsumer); @@ -181,8 +182,8 @@ public class FormsInstrumenter extends FormsBuilder { final ClassReader classReader = new ClassReader(originalContent.getBuffer(), originalContent.getOffset(), originalContent.getLength()); - final int version = getClassFileVersion(classReader); - final InstrumenterClassWriter classWriter = new InstrumenterClassWriter(getAsmClassWriterFlags(version), finder); + final int version = BaseInstrumentingBuilder.getClassFileVersion(classReader); + final InstrumenterClassWriter classWriter = new InstrumenterClassWriter(BaseInstrumentingBuilder.getAsmClassWriterFlags(version), finder); final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, finder, nestedFormsLoader, false, classWriter); final byte[] patchedBytes = codeGenerator.patchClass(classReader); if (patchedBytes != null) { @@ -241,51 +242,6 @@ public class FormsInstrumenter extends FormsBuilder { } } - private static int getClassFileVersion(ClassReader reader) { - final Ref result = new Ref(0); - reader.accept(new ClassVisitor(Opcodes.ASM4) { - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - result.set(version); - } - }, 0); - return result.get(); - } - - private static int getAsmClassWriterFlags(int version) { - return version >= Opcodes.V1_6 && version != Opcodes.V1_1 ? ClassWriter.COMPUTE_FRAMES : ClassWriter.COMPUTE_MAXS; - } - - private static InstrumentationClassFinder createInstrumentationClassFinder( - Collection platformCp, Collection cp, Map sourcePath, final OutputConsumer outputConsumer - ) throws MalformedURLException { - - final URL[] platformUrls = new URL[platformCp.size()]; - int index = 0; - for (File file : platformCp) { - platformUrls[index++] = file.toURI().toURL(); - } - - final List urls = new ArrayList(cp.size() + sourcePath.size() + 1); - for (File file : cp) { - urls.add(file.toURI().toURL()); - } - urls.add(getResourcePath(GridConstraints.class).toURI().toURL()); // forms_rt.jar - - for (File file : sourcePath.keySet()) { // sourcepath for loading forms resources - urls.add(file.toURI().toURL()); - } - - return new InstrumentationClassFinder(platformUrls, urls.toArray(new URL[urls.size()])) { - protected InputStream lookupClassBeforeClasspath(String internalClassName) { - final BinaryContent content = outputConsumer.lookupClassBytes(internalClassName.replace("/", ".")); - if (content != null) { - return new ByteArrayInputStream(content.getBuffer(), content.getOffset(), content.getLength()); - } - return null; - } - }; - } - private static File getResourcePath(Class aClass) { return new File(PathManager.getResourceRoot(aClass, "/" + aClass.getName().replace('.', '/') + ".class")); }