Skip to content

Commit 8aaa455

Browse files
authored
Merge pull request #2441 from usethesource/feat/reduce-module-environment-lookup
Add loopup caches in ModuleEnvironment to improve execution speed
2 parents 3cb5ead + 1641294 commit 8aaa455

File tree

3 files changed

+103
-61
lines changed

3 files changed

+103
-61
lines changed

src/org/rascalmpl/interpreter/Evaluator.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ public void notifyConstructorDeclaredListeners() {
372372
}
373373
}
374374
constructorDeclaredListeners.clear();
375+
getHeap().clearLookupChaches();
375376
}
376377

377378
@Override

src/org/rascalmpl/interpreter/env/GlobalEnvironment.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public void registerSourceResolver(String scheme, ICallableValue function) {
9595
*/
9696
public ModuleEnvironment addModule(ModuleEnvironment mod) {
9797
assert mod != null;
98+
clearLookupChaches();
9899
ModuleEnvironment env = moduleEnvironment.get(mod.getName());
99100
if (env == null) {
100101
moduleEnvironment.put(mod.getName(), mod);
@@ -111,6 +112,7 @@ else if (env == mod) {
111112
public ModuleEnvironment resetModule(String name) {
112113
ModuleEnvironment mod = moduleEnvironment.get(name);
113114
mod.reset();
115+
clearLookupChaches();
114116
return mod;
115117
}
116118

@@ -146,7 +148,11 @@ public String toString(){
146148
}
147149

148150
public void removeModule(ModuleEnvironment env) {
149-
moduleEnvironment.remove(env.getName());
151+
var name = env.getName();
152+
moduleEnvironment.remove(name);
153+
for (var mod : moduleEnvironment.values()) {
154+
mod.removeModule(name);
155+
}
150156
}
151157

152158
public void setModuleURI(String name, URI location) {
@@ -237,4 +243,8 @@ public boolean isBootstrapper() {
237243
public List<String> getExtendCycle() {
238244
return Collections.unmodifiableList(extendStack.stream().collect(Collectors.toList()));
239245
}
246+
247+
public void clearLookupChaches() {
248+
moduleEnvironment.values().forEach(ModuleEnvironment::clearLookupCaches);
249+
}
240250
}

src/org/rascalmpl/interpreter/env/ModuleEnvironment.java

Lines changed: 91 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,18 @@
1717
*******************************************************************************/
1818
package org.rascalmpl.interpreter.env;
1919

20+
import java.util.ArrayList;
2021
import java.util.Collection;
2122
import java.util.Collections;
2223
import java.util.HashMap;
2324
import java.util.HashSet;
25+
import java.util.Iterator;
2426
import java.util.LinkedHashSet;
2527
import java.util.LinkedList;
2628
import java.util.List;
2729
import java.util.Map;
30+
import java.util.Map.Entry;
31+
import java.util.Optional;
2832
import java.util.Set;
2933
import java.util.function.Predicate;
3034

@@ -67,7 +71,8 @@
6771
*/
6872
public class ModuleEnvironment extends Environment {
6973
protected final GlobalEnvironment heap;
70-
protected Set<String> importedModules;
74+
/** Map of imported modules to resolved ModuleEnvironments, will only be empty in case of a module was in a cycle or got reloaded and failed during the reload. use {@link #importedModulesResolved} to lazily resolve the modules. */
75+
protected Map<String, Optional<ModuleEnvironment>> importedModules;
7176
protected Set<String> extended;
7277
protected TypeStore typeStore;
7378
protected Set<IValue> productions;
@@ -79,6 +84,7 @@ public class ModuleEnvironment extends Environment {
7984
private String deprecated;
8085
protected Map<String, AbstractFunction> resourceImporters;
8186
protected Map<Type, Set<GenericKeywordParameters>> cachedGeneralKeywordParameters;
87+
protected Map<String, List<AbstractFunction>> cachedPublicFunctions;
8288

8389
protected static final TypeFactory TF = TypeFactory.getInstance();
8490

@@ -87,7 +93,7 @@ public class ModuleEnvironment extends Environment {
8793
public ModuleEnvironment(String name, GlobalEnvironment heap) {
8894
super(ValueFactoryFactory.getValueFactory().sourceLocation(URIUtil.assumeCorrect("main", name, "")), name);
8995
this.heap = heap;
90-
this.importedModules = new HashSet<String>();
96+
this.importedModules = new HashMap<>();
9197
this.concreteSyntaxTypes = new HashMap<String, NonTerminalType>();
9298
this.productions = new HashSet<IValue>();
9399
this.generalKeywordParameters = new HashMap<Type,List<KeywordFormal>>();
@@ -97,6 +103,7 @@ public ModuleEnvironment(String name, GlobalEnvironment heap) {
97103
this.bootstrap = false;
98104
this.resourceImporters = new HashMap<String, AbstractFunction>();
99105
this.cachedGeneralKeywordParameters = null;
106+
this.cachedPublicFunctions = null;
100107
}
101108

102109
/**
@@ -116,13 +123,14 @@ protected ModuleEnvironment(ModuleEnvironment env) {
116123
this.bootstrap = env.bootstrap;
117124
this.resourceImporters = env.resourceImporters;
118125
this.cachedGeneralKeywordParameters = null;
126+
this.cachedPublicFunctions = null;
119127
this.deprecated = env.deprecated;
120128
}
121129

122130
@Override
123131
public void reset() {
124132
super.reset();
125-
this.importedModules = new HashSet<>();
133+
this.importedModules = new HashMap<>();
126134
this.concreteSyntaxTypes = new HashMap<>();
127135
this.typeStore = new TypeStore();
128136
this.productions = new HashSet<IValue>();
@@ -133,6 +141,13 @@ public void reset() {
133141
this.deprecated = null;
134142
this.generalKeywordParameters = new HashMap<>();
135143
this.cachedGeneralKeywordParameters = null;
144+
this.cachedPublicFunctions = null;
145+
}
146+
147+
public void clearLookupCaches() {
148+
importedModules.replaceAll((k, v) -> Optional.empty());
149+
cachedGeneralKeywordParameters = null;
150+
cachedPublicFunctions = null;
136151
}
137152

138153
public void extend(ModuleEnvironment other) {
@@ -142,9 +157,9 @@ public void extend(ModuleEnvironment other) {
142157
// so that types become available
143158
if (other.importedModules != null) {
144159
if (this.importedModules == null) {
145-
this.importedModules = new HashSet<String>();
160+
this.importedModules = new HashMap<>();
146161
}
147-
this.importedModules.addAll(other.importedModules);
162+
this.importedModules.putAll(other.importedModules);
148163
}
149164

150165
if (other.concreteSyntaxTypes != null) {
@@ -294,7 +309,7 @@ public IMap getSyntaxDefinition() {
294309
result.put(VF.string(m), t);
295310
}else if(m.equals(getName())) { // This is the root scope.
296311
ISetWriter importWriter = VF.setWriter();
297-
for(String impname : importedModules){
312+
for(String impname : importedModules.keySet()){
298313
if(!done.contains(impname)) todo.add(impname);
299314

300315
importWriter.insert(VF.string(impname));
@@ -327,15 +342,25 @@ public boolean isModuleEnvironment() {
327342

328343
public void addImport(String name, ModuleEnvironment env) {
329344
assert heap.getModule(name).equals(env);
330-
importedModules.add(name);
345+
importedModules.put(name, Optional.ofNullable(env));
331346
typeStore.importStore(env.typeStore);
347+
this.cachedGeneralKeywordParameters = null;
348+
this.cachedPublicFunctions = null;
349+
}
350+
351+
void removeModule(String name) {
352+
importedModules.computeIfPresent(name, (k, v) -> Optional.empty());
353+
this.cachedGeneralKeywordParameters = null;
354+
this.cachedPublicFunctions = null;
332355
}
333356

334357
public void addExtend(String name) {
335358
if (extended == null) {
336359
extended = new HashSet<String>();
337360
}
338361
extended.add(name);
362+
this.cachedGeneralKeywordParameters = null;
363+
this.cachedPublicFunctions = null;
339364
}
340365

341366
public List<AbstractFunction> getTests() {
@@ -356,7 +381,7 @@ public List<AbstractFunction> getTests() {
356381

357382
@Override
358383
public Set<String> getImports() {
359-
return Collections.unmodifiableSet(importedModules);
384+
return Collections.unmodifiableSet(importedModules.keySet());
360385
}
361386

362387
public Set<String> getImportsTransitive() {
@@ -384,18 +409,18 @@ public Set<String> getImportsTransitive() {
384409
}
385410

386411
public void unImport(String moduleName) {
387-
if (importedModules.remove(moduleName)) {
388-
ModuleEnvironment old = heap.getModule(moduleName);
389-
if (old != null) {
390-
typeStore.unimportStores(new TypeStore[] { old.getStore() });
391-
}
412+
var old = importedModules.remove(moduleName);
413+
if (old != null && old.isPresent()) {
414+
typeStore.unimportStores(old.get().getStore());
392415
}
393416
cachedGeneralKeywordParameters = null;
417+
cachedPublicFunctions = null;
394418
}
395419

396420
public void unExtend(String moduleName) {
397421
extended.remove(moduleName);
398422
cachedGeneralKeywordParameters = null;
423+
cachedPublicFunctions = null;
399424
}
400425

401426
@Override
@@ -447,6 +472,7 @@ public Result<IValue> getVariable(QualifiedName name) {
447472

448473
return getFrameVariable(cons);
449474
}
475+
450476

451477
@Override
452478
public void storeVariable(String name, Result<IValue> value) {
@@ -461,8 +487,7 @@ public void storeVariable(String name, Result<IValue> value) {
461487
super.storeVariable(name, value);
462488
}
463489
else {
464-
for (String i : importedModules) {
465-
ModuleEnvironment module = heap.getModule(i);
490+
for (ModuleEnvironment module : importedModulesResolved) {
466491
result = module.getLocalPublicVariable(name);
467492

468493
if (result != null) {
@@ -483,8 +508,7 @@ public org.rascalmpl.interpreter.result.Result<IValue> getSimpleVariable(String
483508
return var;
484509
}
485510

486-
for (String moduleName : importedModules) {
487-
ModuleEnvironment mod = getImport(moduleName);
511+
for (ModuleEnvironment mod : importedModulesResolved) {
488512

489513
if (mod != null) {
490514
var = mod.getLocalPublicVariable(name);
@@ -511,8 +535,7 @@ protected Map<String,Result<IValue>> getVariableDefiningEnvironment(String name)
511535
}
512536
}
513537

514-
for (String moduleName : importedModules) {
515-
ModuleEnvironment mod = getImport(moduleName);
538+
for (ModuleEnvironment mod : importedModulesResolved) {
516539
Result<IValue> r = null;
517540
if (mod != null && mod.variableEnvironment != null)
518541
r = mod.variableEnvironment.get(name);
@@ -527,32 +550,36 @@ protected Map<String,Result<IValue>> getVariableDefiningEnvironment(String name)
527550

528551
@Override
529552
public void getAllFunctions(String name, List<AbstractFunction> collection) {
530-
super.getAllFunctions(name, collection);
531-
532-
for (String moduleName : importedModules) {
533-
ModuleEnvironment mod = getImport(moduleName);
553+
collection.addAll(lookupCachedFunctions(name));
554+
}
555+
556+
private List<AbstractFunction> lookupCachedFunctions(String name) {
557+
if (cachedPublicFunctions == null) {
558+
cachedPublicFunctions = io.usethesource.capsule.Map.Transient.of();
559+
}
560+
return cachedPublicFunctions.computeIfAbsent(name, n -> {
561+
var result = new ArrayList<AbstractFunction>();
562+
super.getAllFunctions(n, result);
534563

535-
if (mod != null) {
536-
mod.getLocalPublicFunctions(name, collection);
564+
for (ModuleEnvironment mod : importedModulesResolved) {
565+
566+
if (mod != null) {
567+
mod.getLocalPublicFunctions(n, result);
568+
}
537569
}
538-
}
570+
return result;
571+
});
539572
}
540573

541574
@Override
542575
public void getAllFunctions(Type returnType, String name, List<AbstractFunction> collection) {
543-
super.getAllFunctions(returnType, name, collection);
544-
545-
for (String moduleName : importedModules) {
546-
ModuleEnvironment mod = getImport(moduleName);
547-
548-
if (mod != null) {
549-
mod.getLocalPublicFunctions(returnType, name, collection);
576+
for (var function: lookupCachedFunctions(name)) {
577+
if (function.getReturnType().comparable(returnType)) {
578+
collection.add(function);
550579
}
551580
}
552581
}
553582

554-
555-
556583

557584
private Result<IValue> getLocalPublicVariable(String name) {
558585
Result<IValue> var = null;
@@ -578,20 +605,6 @@ private void getLocalPublicFunctions(String name, List<AbstractFunction> collect
578605
}
579606
}
580607
}
581-
582-
private void getLocalPublicFunctions(Type returnType, String name, List<AbstractFunction> collection) {
583-
if (functionEnvironment != null && !isNamePrivate(name)) {
584-
LinkedHashSet<AbstractFunction> lst = functionEnvironment.get(name);
585-
586-
if (lst != null) {
587-
for (AbstractFunction func : lst) {
588-
if (returnType.isSubtypeOf(func.getReturnType())) {
589-
collection.add(func);
590-
}
591-
}
592-
}
593-
}
594-
}
595608

596609
@Override
597610
public Type abstractDataType(String name, Type... parameters) {
@@ -732,8 +745,7 @@ public Set<GenericKeywordParameters> lookupGenericKeywordParameters(Type adt) {
732745
result.add(new GenericKeywordParameters(this, list, getStore().getKeywordParameters(adt)));
733746
}
734747

735-
for (String moduleName : importedModules) {
736-
ModuleEnvironment mod = getImport(moduleName);
748+
for (ModuleEnvironment mod : importedModulesResolved) {
737749

738750
list = mod.generalKeywordParameters.get(adt);
739751
if (list != null) {
@@ -825,13 +837,33 @@ public String toString() {
825837

826838
@Override
827839
public ModuleEnvironment getImport(String moduleName) {
828-
if(importedModules.contains(moduleName)) {
829-
return heap.getModule(moduleName);
830-
}
831-
else {
832-
return null;
840+
var result = importedModules.computeIfPresent(moduleName,
841+
(m, c) -> c.isPresent() ? c : Optional.ofNullable(heap.getModule(m))
842+
);
843+
if (result == null || result.isEmpty()) {
844+
return null;
833845
}
846+
return result.get();
834847
}
848+
849+
private Iterable<ModuleEnvironment> importedModulesResolved =
850+
() -> new Iterator<ModuleEnvironment>() {
851+
Iterator<Entry<String, Optional<ModuleEnvironment>>> iterator = importedModules.entrySet().iterator();
852+
@Override
853+
public boolean hasNext() {
854+
return iterator.hasNext();
855+
}
856+
@Override
857+
public ModuleEnvironment next() {
858+
var entry = iterator.next();
859+
var result = entry.getValue();
860+
if (result.isEmpty()) {
861+
result = Optional.ofNullable(heap.getModule(entry.getKey()));
862+
entry.setValue(result);
863+
}
864+
return result.orElse(null);
865+
}
866+
};
835867

836868
@Override
837869
public void storeVariable(QualifiedName name, Result<IValue> result) {
@@ -870,8 +902,7 @@ public Type lookupConcreteSyntaxType(String name) {
870902
Type type = concreteSyntaxTypes.get(name);
871903

872904
if (type == null) {
873-
for (String i : importedModules) {
874-
ModuleEnvironment mod = getImport(i);
905+
for (ModuleEnvironment mod : importedModulesResolved) {
875906

876907
if (mod == null) {
877908
continue;
@@ -989,8 +1020,7 @@ protected Environment getFlagsEnvironment(String name) {
9891020
return env;
9901021
}
9911022

992-
for (String moduleName : importedModules) {
993-
ModuleEnvironment mod = getImport(moduleName);
1023+
for (ModuleEnvironment mod : importedModulesResolved) {
9941024
if(mod == null) {
9951025
throw new RuntimeException("getFlagsEnvironment");
9961026
}
@@ -1081,4 +1111,5 @@ public void resetProductions() {
10811111
public Set<IValue> getProductions() {
10821112
return productions;
10831113
}
1114+
10841115
}

0 commit comments

Comments
 (0)