Skip to content

Commit

Permalink
[GR-55261] Backporting: Remove Unreachable Globs from Trie
Browse files Browse the repository at this point in the history
PullRequest: graal/18466
  • Loading branch information
dnestoro authored and ansalond committed Jul 31, 2024
2 parents 7be54ef + 7c359fc commit 9a99942
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.regex.Pattern;

import org.graalvm.nativeimage.Platform;
Expand Down Expand Up @@ -123,7 +124,6 @@ public static GlobTrieNode build(List<GlobWithInfo> patterns) {
starPatterns.forEach(pattern -> addPattern(root, pattern));
noStarPatterns.forEach(pattern -> addPattern(root, pattern));

root.trim();
return root;
}

Expand Down Expand Up @@ -340,6 +340,13 @@ private static int comparePatterns(GlobWithInfo n1, GlobWithInfo n2) {
}
}

/**
* Trims the Trie and makes it unmodifiable.
*/
public static void finalize(GlobTrieNode root) {
root.trim();
}

/**
* Returns list of information from all glob patterns that could match given text.
*/
Expand Down Expand Up @@ -708,4 +715,36 @@ private static SquashedParts getThisLevel(List<GlobTrieNode> parts, int begin) {
private static boolean patternReachedEnd(int index, List<GlobTrieNode> parts) {
return index >= parts.size();
}

public static void removeNodes(GlobTrieNode head, Predicate<String> shouldRemove) {
List<String> contentToRemove = head.getAdditionalContent().stream().filter(shouldRemove).toList();
head.removeAdditionalContent(contentToRemove);

List<GlobTrieNode> childrenToRemove = new ArrayList<>();
for (GlobTrieNode child : head.getChildren()) {
removeNodes(child, shouldRemove);

/* leaf without additional content should be removed */
if (child.isLeaf() && child.getAdditionalContent().isEmpty()) {
if (child.getChildren().isEmpty()) {
/* if it is the last node remove it physically */
childrenToRemove.add(child);
} else {
/*
* the child still has children, but it terminated some pattern => don't remove
* it, just say that it doesn't terminate any pattern anymore
*/
child.makeNodeInternal();
}
continue;
}

/* internal node without children should be removed */
if (!child.isLeaf() && child.getChildren().isEmpty()) {
childrenToRemove.add(child);
}
}

head.removeChildren(childrenToRemove);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,20 @@
import java.util.Map;
import java.util.Set;

import com.oracle.svm.core.heap.UnknownObjectField;

public class GlobTrieNode {
protected static final String STAR = "*";
protected static final String STAR_STAR = "**";
protected static final String LEVEL_IDENTIFIER = "/";
public static final String SAME_LEVEL_IDENTIFIER = "#";

private String content;
@UnknownObjectField(fullyQualifiedTypes = {"java.util.HashMap", "java.util.ImmutableCollections$MapN", "java.util.ImmutableCollections$Map1"}) //
private Map<String, GlobTrieNode> children;
private boolean isLeaf;
private boolean isNewLevel;
@UnknownObjectField(fullyQualifiedTypes = {"java.util.HashSet", "java.util.ImmutableCollections$SetN", "java.util.ImmutableCollections$Set12"}) //
private Set<String> additionalContent;

protected GlobTrieNode() {
Expand Down Expand Up @@ -72,6 +76,10 @@ protected void setLeaf() {
isLeaf = true;
}

protected void makeNodeInternal() {
isLeaf = false;
}

public String getContent() {
return content;
}
Expand All @@ -80,6 +88,10 @@ protected Set<String> getAdditionalContent() {
return additionalContent;
}

protected void removeAdditionalContent(List<String> ac) {
additionalContent.removeAll(ac);
}

protected void addAdditionalContent(String ac) {
this.additionalContent.add(ac);
}
Expand All @@ -92,6 +104,19 @@ protected GlobTrieNode getChild(String child) {
return children.get(child);
}

protected void removeChildren(List<GlobTrieNode> childKeys) {
for (var child : childKeys) {
/*
* we need exact name of the child key in order to delete it. In case when we have a
* complex level (with stars), all children from the same level will have
* SAME_LEVEL_IDENTIFIER, so we must append it here
*/
String sameLevel = !child.isNewLevel() ? SAME_LEVEL_IDENTIFIER : "";
String childKey = child.getContent() + sameLevel;
children.remove(childKey);
}
}

protected GlobTrieNode getChildFromSameLevel(String child) {
return children.get(child + SAME_LEVEL_IDENTIFIER);
}
Expand Down Expand Up @@ -142,5 +167,4 @@ protected void trim() {
additionalContent = Set.copyOf(additionalContent);
children = Map.copyOf(children);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,11 @@ public void afterAnalysis(AfterAnalysisAccess access) {

BuildArtifacts.singleton().add(BuildArtifacts.ArtifactType.BUILD_INFO, reportLocation);
}

/* prepare resources GlobTrie for runtime */
GlobTrieNode root = ImageSingletons.lookup(GlobTrieNode.class);
CompressedGlobTrie.removeNodes(root, (type) -> !access.isReachable(access.findClassByName(type)));
CompressedGlobTrie.finalize(root);
}

@Override
Expand Down

0 comments on commit 9a99942

Please sign in to comment.