JPS mappings for incremental compilation refactoring: reduce disk space requirements by storing lookup usages on per-file basis in FileNode

GitOrigin-RevId: 11586812ca7addc07059b61c1af38c214b9e1170
This commit is contained in:
Eugene Zhuravlev
2024-05-11 12:54:56 +02:00
committed by intellij-monorepo-bot
parent 50a0ed9373
commit 32ee7f2b30
2 changed files with 51 additions and 34 deletions

View File

@@ -3,6 +3,7 @@ package org.jetbrains.jps.builders.java;
import com.intellij.openapi.util.Pair;
import com.intellij.util.SmartList;
import kotlinx.metadata.*;
import org.jetbrains.jps.builders.java.dependencyView.Callbacks;
import org.jetbrains.jps.dependency.*;
import org.jetbrains.jps.dependency.java.*;
@@ -21,6 +22,7 @@ final class BackendCallbackToGraphDeltaAdapter implements Callbacks.Backend {
private final Map<String, Set<Usage>> myAdditionalUsages = Collections.synchronizedMap(new HashMap<>());
private final Map<Path, Set<Usage>> myPerSourceAdditionalUsages = Collections.synchronizedMap(new HashMap<>());
private final List<Pair<Node<?, ?>, Iterable<NodeSource>>> myNodes = new ArrayList<>();
private final Map<NodeSource, Set<Usage>> mySelfUsages = new HashMap<>();
private final GraphConfiguration myGraphConfig;
BackendCallbackToGraphDeltaAdapter(GraphConfiguration graphConfig) {
@@ -44,30 +46,63 @@ final class BackendCallbackToGraphDeltaAdapter implements Callbacks.Backend {
builder.addUsage(usage);
}
}
for (Usage usage : Iterators.flat(Iterators.map(sources, src -> myPerSourceAdditionalUsages.get(Path.of(src))))) {
builder.addUsage(usage);
}
var node = builder.getResult();
List<NodeSource> nodeSources = Iterators.collect(Iterators.map(sources, myGraphConfig.getPathMapper()::toNodeSource), new SmartList<>());
Iterable<LookupNameUsage> lookups = Iterators.flat(Iterators.map(node.getMetadata(KotlinMeta.class), meta -> {
KmDeclarationContainer container = meta.getDeclarationContainer();
final JvmNodeReferenceID owner;
LookupNameUsage clsUsage = null;
if (container instanceof KmPackage) {
owner = new JvmNodeReferenceID(JvmClass.getPackageName(node.getName()));
}
else if (container instanceof KmClass) {
owner = new JvmNodeReferenceID(((KmClass)container).getName());
String ownerName = owner.getNodeName();
String scopeName = JvmClass.getPackageName(ownerName);
String symbolName = scopeName.isEmpty()? ownerName : ownerName.substring(scopeName.length() + 1);
clsUsage = new LookupNameUsage(scopeName, symbolName);
}
else {
owner = null;
}
if (owner == null) {
return Collections.emptyList();
}
Iterable<LookupNameUsage> memberLookups =
Iterators.map(Iterators.unique(Iterators.flat(Iterators.map(container.getFunctions(), KmFunction::getName), Iterators.map(container.getProperties(), KmProperty::getName))), name -> new LookupNameUsage(owner, name));
return clsUsage == null? memberLookups : Iterators.flat(Iterators.asIterable(clsUsage), memberLookups);
}));
for (LookupNameUsage lookup : lookups) {
for (NodeSource src : nodeSources) {
mySelfUsages.computeIfAbsent(src, s -> new HashSet<>()).add(lookup);
}
}
if (!node.isPrivate()) {
myNodes.add(new Pair<>(node, Iterators.collect(Iterators.map(sources, myGraphConfig.getPathMapper()::toNodeSource), new SmartList<>())));
myNodes.add(new Pair<>(node, nodeSources));
}
}
public List<Pair<Node<?, ?>, Iterable<NodeSource>>> getNodes() {
try {
if (!myPerSourceAdditionalUsages.isEmpty()) {
NodeSourcePathMapper pathMapper = myGraphConfig.getPathMapper();
for (NodeSource source : Iterators.flat(Iterators.map(myNodes, p -> p.getSecond()))) {
myPerSourceAdditionalUsages.remove(pathMapper.toPath(source));
}
for (Map.Entry<Path, Set<Usage>> entry : myPerSourceAdditionalUsages.entrySet()) {
NodeSource src = pathMapper.toNodeSource(entry.getKey());
myNodes.add(new Pair<>(new FileNode(src.toString(), entry.getValue()), List.of(src)));
Set<Usage> usages = entry.getValue();
Set<Usage> selfUsages = mySelfUsages.get(src);
if (selfUsages != null) {
usages.removeAll(selfUsages);
}
return myNodes;
myNodes.add(new Pair<>(new FileNode(src.toString(), usages), List.of(src)));
}
finally {
myPerSourceAdditionalUsages.clear();
}
return myNodes;
}
@Override

View File

@@ -5,7 +5,10 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Ref;
import com.intellij.util.ArrayUtil;
import com.intellij.util.SmartList;
import kotlinx.metadata.*;
import kotlinx.metadata.Attributes;
import kotlinx.metadata.KmDeclarationContainer;
import kotlinx.metadata.KmFunction;
import kotlinx.metadata.KmProperty;
import kotlinx.metadata.jvm.JvmExtensionsKt;
import kotlinx.metadata.jvm.JvmMethodSignature;
import org.jetbrains.annotations.NotNull;
@@ -491,27 +494,6 @@ public final class JvmClassNodeBuilder extends ClassVisitor implements NodeBuild
}
}
// remove own members lookups
KmDeclarationContainer container = findKotlinDeclarationContainer();
if (container != null) {
JvmNodeReferenceID owner = null;
if (container instanceof KmPackage) {
owner = new JvmNodeReferenceID(JvmClass.getPackageName(myName));
}
else if (container instanceof KmClass) {
owner = new JvmNodeReferenceID(((KmClass)container).getName());
String nodeName = owner.getNodeName();
String scopeName = JvmClass.getPackageName(nodeName);
String symbolName = scopeName.isEmpty()? nodeName : nodeName.substring(scopeName.length() + 1);
myUsages.remove(new LookupNameUsage(scopeName, symbolName));
}
if (owner != null) {
for (String name : Iterators.unique(Iterators.flat(Iterators.map(container.getFunctions(), KmFunction::getName), Iterators.map(container.getProperties(), KmProperty::getName)))) {
myUsages.remove(new LookupNameUsage(owner, name));
}
}
}
return new JvmClass(flags, mySignature, myName, myFileName, mySuperClass, myOuterClassName.get(), myInterfaces, myFields, myMethods, myAnnotations, myTargets, myRetentionPolicy, myUsages, myMetadata);
}