mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
class processing builder generalization
This commit is contained in:
+1
-1
@@ -238,7 +238,7 @@ public class InstrumentationClassFinder {
|
||||
return superClass != null? loadClass(superClass) : null;
|
||||
}
|
||||
|
||||
private PseudoClass[] getInterfaces() throws IOException, ClassNotFoundException {
|
||||
public PseudoClass[] getInterfaces() throws IOException, ClassNotFoundException {
|
||||
if (myInterfaces == null) {
|
||||
return EMPTY_PSEUDOCLASS_ARRAY;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.jetbrains.jps.javac.BinaryContent;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@@ -21,11 +22,21 @@ class ChunkBuildOutputConsumerImpl implements ModuleLevelBuilder.OutputConsumer
|
||||
private final CompileContext myContext;
|
||||
private Map<BuildTarget<?>, BuildOutputConsumerImpl> myTarget2Consumer = new THashMap<BuildTarget<?>, BuildOutputConsumerImpl>();
|
||||
private Map<String, CompiledClass> myClasses = new THashMap<String, CompiledClass>();
|
||||
private Map<BuildTarget<?>, Collection<CompiledClass>> myTargetToClassesMap = new THashMap<BuildTarget<?>, Collection<CompiledClass>>();
|
||||
|
||||
public ChunkBuildOutputConsumerImpl(CompileContext context) {
|
||||
myContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<CompiledClass> getTargetCompiledClasses(BuildTarget<?> target) {
|
||||
final Collection<CompiledClass> classes = myTargetToClassesMap.get(target);
|
||||
if (classes != null) {
|
||||
return Collections.unmodifiableCollection(classes);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Map<String, CompiledClass> getCompiledClasses() {
|
||||
@@ -43,6 +54,12 @@ class ChunkBuildOutputConsumerImpl implements ModuleLevelBuilder.OutputConsumer
|
||||
public void registerCompiledClass(BuildTarget<?> target, CompiledClass compiled) throws IOException {
|
||||
if (compiled.getClassName() != null) {
|
||||
myClasses.put(compiled.getClassName(), compiled);
|
||||
Collection<CompiledClass> classes = myTargetToClassesMap.get(target);
|
||||
if (classes == null) {
|
||||
classes = new ArrayList<CompiledClass>();
|
||||
myTargetToClassesMap.put(target, classes);
|
||||
}
|
||||
classes.add(compiled);
|
||||
}
|
||||
registerOutputFile(target, compiled.getOutputFile(), Collections.<String>singleton(compiled.getSourceFile().getPath()));
|
||||
}
|
||||
@@ -66,5 +83,6 @@ class ChunkBuildOutputConsumerImpl implements ModuleLevelBuilder.OutputConsumer
|
||||
public void clear() {
|
||||
myTarget2Consumer.clear();
|
||||
myClasses.clear();
|
||||
myTargetToClassesMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ public abstract class ModuleLevelBuilder extends Builder {
|
||||
|
||||
void registerCompiledClass(BuildTarget<?> target, CompiledClass compiled) throws IOException;
|
||||
|
||||
Collection<CompiledClass> getTargetCompiledClasses(BuildTarget<?> target);
|
||||
@NotNull
|
||||
Map<String, CompiledClass> getCompiledClasses();
|
||||
|
||||
|
||||
+16
-123
@@ -2,111 +2,45 @@ 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.incremental.BuilderCategory;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.incremental.CompiledClass;
|
||||
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<InstrumentationClassFinder> CLASS_FINDER = Key.create("_cached_instrumentation_class_finder_");
|
||||
public abstract class BaseInstrumentingBuilder extends ClassProcessingBuilder {
|
||||
|
||||
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<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder, OutputConsumer outputConsumer) throws ProjectBuildException, IOException {
|
||||
protected final ExitCode performBuild(CompileContext context, ModuleChunk chunk, InstrumentationClassFinder finder, OutputConsumer outputConsumer) {
|
||||
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<File> platformCp = paths.getPlatformCompilationClasspath(chunk, false);
|
||||
|
||||
final Collection<File> classpath = new ArrayList<File>();
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (shouldShowProgress) {
|
||||
context.processMessage(new ProgressMessage("")); // cleanup progress
|
||||
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;
|
||||
}
|
||||
}
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
protected abstract boolean isEnabled(CompileContext context, ModuleChunk chunk);
|
||||
|
||||
protected abstract boolean canInstrument(CompiledClass compiledClass, int classFileVersion);
|
||||
|
||||
@Nullable
|
||||
@@ -116,45 +50,4 @@ public abstract class BaseInstrumentingBuilder extends ModuleLevelBuilder{
|
||||
ClassWriter writer,
|
||||
InstrumentationClassFinder finder);
|
||||
|
||||
protected abstract String getProgressMessage();
|
||||
// utility methods
|
||||
|
||||
public static InstrumentationClassFinder createInstrumentationClassFinder(Collection<File> platformCp, Collection<File> 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<Integer> result = new Ref<Integer>(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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
package org.jetbrains.jps.incremental.instrumentation;
|
||||
|
||||
import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
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/30/12
|
||||
*/
|
||||
public abstract class ClassProcessingBuilder extends ModuleLevelBuilder {
|
||||
private static final Key<InstrumentationClassFinder> CLASS_FINDER = Key.create("_cached_instrumentation_class_finder_");
|
||||
|
||||
public ClassProcessingBuilder(BuilderCategory category) {
|
||||
super(category);
|
||||
}
|
||||
|
||||
protected abstract boolean isEnabled(CompileContext context, ModuleChunk chunk);
|
||||
|
||||
protected abstract String getProgressMessage();
|
||||
|
||||
@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<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder, OutputConsumer outputConsumer) throws ProjectBuildException, IOException {
|
||||
if (outputConsumer.getCompiledClasses().isEmpty() || !isEnabled(context, chunk)) {
|
||||
return ExitCode.NOTHING_DONE;
|
||||
}
|
||||
|
||||
final String progress = getProgressMessage();
|
||||
final boolean shouldShowProgress = !StringUtil.isEmptyOrSpaces(progress);
|
||||
if (shouldShowProgress) {
|
||||
context.processMessage(new ProgressMessage(progress + " [" + chunk.getName() + "]"));
|
||||
}
|
||||
|
||||
ExitCode exitCode = ExitCode.NOTHING_DONE;
|
||||
try {
|
||||
InstrumentationClassFinder finder = CLASS_FINDER.get(context); // try using shared finder
|
||||
if (finder == null) {
|
||||
final ProjectPaths paths = context.getProjectPaths();
|
||||
final Collection<File> platformCp = paths.getPlatformCompilationClasspath(chunk, false);
|
||||
|
||||
final Collection<File> classpath = new ArrayList<File>();
|
||||
classpath.addAll(paths.getCompilationClasspath(chunk, false));
|
||||
classpath.addAll(ProjectPaths.getSourceRootsWithDependents(chunk).keySet());
|
||||
|
||||
finder = createInstrumentationClassFinder(platformCp, classpath, outputConsumer);
|
||||
CLASS_FINDER.set(context, finder);
|
||||
}
|
||||
|
||||
exitCode = performBuild(context, chunk, finder, outputConsumer);
|
||||
}
|
||||
finally {
|
||||
if (shouldShowProgress) {
|
||||
context.processMessage(new ProgressMessage("")); // cleanup progress
|
||||
}
|
||||
}
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
protected abstract ExitCode performBuild(CompileContext context, ModuleChunk chunk, InstrumentationClassFinder finder, OutputConsumer outputConsumer);
|
||||
|
||||
|
||||
// utility methods
|
||||
public static InstrumentationClassFinder createInstrumentationClassFinder(Collection<File> platformCp, Collection<File> 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<Integer> result = new Ref<Integer>(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();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user