Skip to content

Commit fdc9824

Browse files
author
dwightguth
committed
Merge pull request runtimeverification#1139 from dwightguth/localsdf
evict stuff from kparser cache Former-commit-id: 906dff26c1fba3bddd5d2418669ba1130056ec17 [formerly ecc59dd334d74d252d8282d31f113ed6f22b5b37] Former-commit-id: 3c33f55afd9f7349c86303f59c193013624494ec
2 parents 32759bd + 36e814d commit fdc9824

1 file changed

Lines changed: 37 additions & 29 deletions

File tree

kernel/src/main/java/org/kframework/parser/concrete/DefinitionLocalKParser.java

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
import java.net.URL;
99
import java.net.URLClassLoader;
1010
import java.util.Arrays;
11-
import java.util.HashMap;
12-
import java.util.Iterator;
11+
import java.util.LinkedHashMap;
1312
import java.util.List;
1413
import java.util.Map;
1514
import java.util.stream.Collectors;
@@ -26,9 +25,9 @@
2625
*
2726
* Note that a consequence of this is that if you use many definitions in
2827
* the same process, you will use up a lot of memory dedicated to the JVM code cache.
29-
* Currently the implementation of this class does not expire classloaders
30-
* when too many of them have been instantiated. It also does not behave correctly
31-
* if a single definition is modified and then parsed again. These are future optimizations
28+
* We get around this by expiring old classes and therefore old classloaders.
29+
* Note that it also does not behave correctly if a single definition is modified
30+
* and then parsed again. This is a future optimization
3231
* that can potentially be made to this class, however, what it does currently
3332
* is sufficient to allow a single process to be used for an entire KTest test suite,
3433
* which is the primary goal of this class.
@@ -38,18 +37,27 @@
3837
*/
3938
public class DefinitionLocalKParser {
4039

41-
private static final Map<File, Class<?>> impl = new HashMap<>();
40+
private static final Map<File, Class<?>> impl = new LinkedHashMap<File, Class<?>>() {
41+
protected boolean removeEldestEntry(Map.Entry<File,java.lang.Class<?>> eldest) {
42+
return size() > Runtime.getRuntime().availableProcessors() * 2;
43+
}
44+
};
45+
46+
private static Class<?> resourceDomain;
4247

43-
public static void init(File kompiled) {
48+
public static Class<?> init(File kompiled) {
4449
ClassLoader cl;
4550
try {
46-
if (impl.containsKey(kompiled.getCanonicalFile())) return;
51+
Class<?> cached = impl.get(kompiled.getCanonicalFile());
52+
if (cached != null) return cached;
4753
cl = new URLClassLoader(new URL[] {
4854
new File(JarInfo.getKBase(false), "lib/java/dynamic/strategoxt.jar").toURI().toURL(),
4955
new File(JarInfo.getKBase(false), "lib/java/dynamic/sdf-parser.jar").toURI().toURL()
5056
});
5157
Class<?> kparser = Class.forName("org.kframework.parser.concrete.KParser", true, cl);
58+
if (resourceDomain == null) resourceDomain = kparser;
5259
impl.put(kompiled.getCanonicalFile(), kparser);
60+
return kparser;
5361
} catch (ClassNotFoundException | IOException e) {
5462
throw KExceptionManager.internalError("Failed to localize JSGLR to a thread", e);
5563
}
@@ -61,37 +69,37 @@ public static void init(File kompiled) {
6169
* @return
6270
*/
6371
public static Class<?> resourceDomain() {
64-
Iterator<Class<?>> i = impl.values().iterator();
65-
assert i.hasNext();
66-
return i.next();
72+
return resourceDomain;
6773
}
6874

69-
private static String invokeReflective(String methodName, File kompiled, Object... args) {
75+
private static String invokeReflective(String methodName, Class<?> kparser, Object... args) {
7076
try {
7177
List<Class<?>> classes = Arrays.asList(args).stream().map(o -> o.getClass()).collect(Collectors.toList());
72-
Method m = impl.get(kompiled.getCanonicalFile()).getMethod(methodName, classes.toArray(new Class<?>[classes.size()]));
78+
Method m = kparser.getMethod(methodName, classes.toArray(new Class<?>[classes.size()]));
7379
return (String) m.invoke(null, args);
74-
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | IOException e) {
80+
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException e) {
7581
throw KExceptionManager.internalError("Failed to localize JSGLR to a thread", e);
82+
} catch (InvocationTargetException e) {
83+
throw new RuntimeException("JSGLR failed to parse term", e);
7684
}
7785
}
7886

7987
public static String ParseKoreString(String kDefinition, File kompiled) {
80-
init(kompiled);
81-
invokeReflective("ImportTblRule", kompiled, kompiled);
82-
return invokeReflective("ParseKoreString", kompiled, kDefinition);
88+
Class<?> kparser = init(kompiled);
89+
invokeReflective("ImportTblRule", kparser, kompiled);
90+
return invokeReflective("ParseKoreString", kparser, kDefinition);
8391
}
8492

8593
public static String ParseKConfigString(String kDefinition, File kompiled) {
86-
init(kompiled);
87-
invokeReflective("ImportTblRule", kompiled, kompiled);
88-
return invokeReflective("ParseKConfigString", kompiled, kDefinition);
94+
Class<?> kparser = init(kompiled);
95+
invokeReflective("ImportTblRule", kparser, kompiled);
96+
return invokeReflective("ParseKConfigString", kparser, kDefinition);
8997
}
9098

9199
public static String ParseKRuleString(String kDefinition, File kompiled) {
92-
init(kompiled);
93-
invokeReflective("ImportTblRule", kompiled, kompiled);
94-
return invokeReflective("ParseKRuleString", kompiled, kDefinition);
100+
Class<?> kparser = init(kompiled);
101+
invokeReflective("ImportTblRule", kparser, kompiled);
102+
return invokeReflective("ParseKRuleString", kparser, kDefinition);
95103
}
96104

97105
/**
@@ -102,14 +110,14 @@ public static String ParseKRuleString(String kDefinition, File kompiled) {
102110
* @return The xml representation of the parsed term, or an error in the xml format.
103111
*/
104112
public static String ParseKCmdString(String argument, File kompiled) {
105-
init(kompiled);
106-
invokeReflective("ImportTblGround", kompiled, kompiled);
107-
return invokeReflective("ParseKCmdString", kompiled, argument);
113+
Class<?> kparser = init(kompiled);
114+
invokeReflective("ImportTblGround", kparser, kompiled);
115+
return invokeReflective("ParseKCmdString", kparser, argument);
108116
}
109117

110118
public static String ParseProgramString(String program, String startSymbol, File kompiled) {
111-
init(kompiled);
112-
invokeReflective("ImportTblPgm", kompiled, kompiled);
113-
return invokeReflective("ParseProgramString", kompiled, program, startSymbol);
119+
Class<?> kparser = init(kompiled);
120+
invokeReflective("ImportTblPgm", kparser, kompiled);
121+
return invokeReflective("ParseProgramString", kparser, program, startSymbol);
114122
}
115123
}

0 commit comments

Comments
 (0)