88import java .net .URL ;
99import java .net .URLClassLoader ;
1010import java .util .Arrays ;
11- import java .util .HashMap ;
12- import java .util .Iterator ;
11+ import java .util .LinkedHashMap ;
1312import java .util .List ;
1413import java .util .Map ;
1514import java .util .stream .Collectors ;
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.
3837 */
3938public 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