More robust work with caches (#8393)

This commit is contained in:
Jaroslav Tulach 2023-11-28 09:03:15 +01:00 committed by GitHub
parent dd28517d9e
commit c889c8e83f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 131 additions and 28 deletions

View File

@ -18,6 +18,7 @@ import org.enso.compiler.core.ir.{
Warning, Warning,
Module => IRModule Module => IRModule
} }
import org.enso.compiler.core.ir.MetadataStorage.MetadataPair
import org.enso.compiler.core.ir.expression.Error import org.enso.compiler.core.ir.expression.Error
import org.enso.compiler.core.ir.module.scope.Export import org.enso.compiler.core.ir.module.scope.Export
import org.enso.compiler.core.ir.module.scope.Import import org.enso.compiler.core.ir.module.scope.Import
@ -587,9 +588,17 @@ class Compiler(
injectSyntheticModuleExports(expr, module.getDirectModulesRefs) injectSyntheticModuleExports(expr, module.getDirectModulesRefs)
val discoveredModule = val discoveredModule =
recognizeBindings(exprWithModuleExports, moduleContext) recognizeBindings(exprWithModuleExports, moduleContext)
if (context.wasLoadedFromCache(module)) {
if (module.getBindingsMap() != null) {
discoveredModule.passData.update(
new MetadataPair(BindingAnalysis, module.getBindingsMap())
)
}
}
context.updateModule( context.updateModule(
module, module,
{ u => { u =>
u.bindingsMap(null);
u.ir(discoveredModule) u.ir(discoveredModule)
u.compilationStage(CompilationStage.AFTER_PARSING) u.compilationStage(CompilationStage.AFTER_PARSING)
u.loadedFromCache(false) u.loadedFromCache(false)

View File

@ -61,6 +61,10 @@ import scala.collection.immutable.Seq;
@Persistable(clazz = Name.BuiltinAnnotation.class, id = 783) @Persistable(clazz = Name.BuiltinAnnotation.class, id = 783)
@Persistable(clazz = Type.Error.class, id = 784) @Persistable(clazz = Type.Error.class, id = 784)
@Persistable(clazz = Unused.Binding.class, id = 785) @Persistable(clazz = Unused.Binding.class, id = 785)
@Persistable(clazz = Unused.PatternBinding.class, id = 786)
@Persistable(clazz = Unused.FunctionArgument.class, id = 787)
@Persistable(clazz = Warning.DuplicatedImport.class, id = 788)
@Persistable(clazz = Warning.WrongBuiltinMethod.class, id = 789)
public final class IrPersistance { public final class IrPersistance {
private IrPersistance() {} private IrPersistance() {}
@ -389,23 +393,15 @@ public final class IrPersistance {
} }
@Override @Override
protected void writeObject(DiagnosticStorage obj, Output out) throws IOException {} protected void writeObject(DiagnosticStorage obj, Output out) throws IOException {
out.writeInline(List.class, obj.toList());
}
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected DiagnosticStorage readObject(Input in) throws IOException, ClassNotFoundException { protected DiagnosticStorage readObject(Input in) throws IOException, ClassNotFoundException {
return new DiagnosticStorage( var diags = in.readInline(List.class);
(scala.collection.immutable.List) scala.collection.immutable.Nil$.MODULE$); return new DiagnosticStorage(diags);
} }
} }
private static <T> scala.collection.immutable.List<T> join(
T head, scala.collection.immutable.List<T> tail) {
return scala.collection.immutable.$colon$colon$.MODULE$.apply(head, tail);
}
@SuppressWarnings("unchecked")
private static <E extends Throwable> E raise(Class<E> clazz, Throwable t) throws E {
throw (E) t;
}
} }

View File

@ -276,7 +276,7 @@ final class TruffleCompilerContext implements CompilerContext {
private final class ModuleUpdater implements Updater, AutoCloseable { private final class ModuleUpdater implements Updater, AutoCloseable {
private final Module module; private final Module module;
private BindingsMap map; private BindingsMap[] map;
private org.enso.compiler.core.ir.Module[] ir; private org.enso.compiler.core.ir.Module[] ir;
private CompilationStage stage; private CompilationStage stage;
private Boolean loadedFromCache; private Boolean loadedFromCache;
@ -289,7 +289,7 @@ final class TruffleCompilerContext implements CompilerContext {
@Override @Override
public void bindingsMap(BindingsMap map) { public void bindingsMap(BindingsMap map) {
this.map = map; this.map = new BindingsMap[] { map };
} }
@Override @Override
@ -320,10 +320,10 @@ final class TruffleCompilerContext implements CompilerContext {
@Override @Override
public void close() { public void close() {
if (map != null) { if (map != null) {
if (module.bindings != null) { if (module.bindings != null && map[0] != null) {
loggerCompiler.log(Level.FINEST, "Reassigining bindings to {0}", module); loggerCompiler.log(Level.FINEST, "Reassigining bindings to {0}", module);
} }
module.bindings = map; module.bindings = map[0];
} }
if (ir != null) { if (ir != null) {
module.module.unsafeSetIr(ir[0]); module.module.unsafeSetIr(ir[0]);

View File

@ -102,7 +102,7 @@ private class DefaultPackageRepository(
/** The mapping between the library and its cached bindings, if already laoded. */ /** The mapping between the library and its cached bindings, if already laoded. */
private val loadedLibraryBindings: collection.mutable.Map[ private val loadedLibraryBindings: collection.mutable.Map[
LibraryName, LibraryName,
ImportExportCache.CachedBindings Option[ImportExportCache.CachedBindings]
] = ] =
collection.mutable.LinkedHashMap() collection.mutable.LinkedHashMap()
@ -578,15 +578,15 @@ private class DefaultPackageRepository(
val cache = ensurePackageIsLoaded(libraryName).toOption.flatMap { _ => val cache = ensurePackageIsLoaded(libraryName).toOption.flatMap { _ =>
if (!loadedLibraryBindings.contains(libraryName)) { if (!loadedLibraryBindings.contains(libraryName)) {
loadedPackages.get(libraryName).flatten.foreach(loadDependencies(_)) loadedPackages.get(libraryName).flatten.foreach(loadDependencies(_))
context val cachedBindingOption = context
.asInstanceOf[TruffleCompilerContext] .asInstanceOf[TruffleCompilerContext]
.getSerializationManager() .getSerializationManager()
.deserializeLibraryBindings(libraryName) .deserializeLibraryBindings(libraryName)
.foreach(cache => loadedLibraryBindings.addOne((libraryName, cache))) loadedLibraryBindings.addOne((libraryName, cachedBindingOption))
} }
loadedLibraryBindings.get(libraryName) loadedLibraryBindings.get(libraryName)
} }
cache.flatMap(_.bindings.findForModule(moduleName)) cache.flatMap(_.flatMap(_.bindings.findForModule(moduleName)))
} }
private def loadDependencies(pkg: Package[TruffleFile]): Unit = { private def loadDependencies(pkg: Package[TruffleFile]): Unit = {

View File

@ -1,22 +1,19 @@
package org.enso.interpreter.caches; package org.enso.interpreter.caches;
import org.enso.compiler.CompilerTest; import org.enso.compiler.CompilerTest;
import org.enso.compiler.core.IR;
import org.enso.interpreter.Constants;
import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.test.TestBase; import org.enso.interpreter.test.TestBase;
import org.enso.interpreter.util.ScalaConversions;
import org.enso.polyglot.CompilationStage; import org.enso.polyglot.CompilationStage;
import org.enso.polyglot.LanguageInfo; import org.enso.polyglot.LanguageInfo;
import org.enso.polyglot.MethodNames; import org.enso.polyglot.MethodNames;
import org.enso.polyglot.RuntimeOptions; import org.enso.polyglot.RuntimeOptions;
import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Context;
import org.junit.Test; import org.graalvm.polyglot.Source;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test;
public class ModuleCacheTest extends TestBase { public class ModuleCacheTest extends TestBase {
private static Context ctx; private static Context ctx;
@ -55,4 +52,30 @@ public class ModuleCacheTest extends TestBase {
assertNotNull("IR read", cachedIr); assertNotNull("IR read", cachedIr);
CompilerTest.assertIR(name, ir, cachedIr.moduleIR()); CompilerTest.assertIR(name, ir, cachedIr.moduleIR());
} }
@Test
public void testCompareWithWarning() throws Exception {
var ensoCtx = (EnsoContext) ctx.getBindings(LanguageInfo.ID).invokeMember(MethodNames.TopScope.LEAK_CONTEXT).asHostObject();
var name = "TestWarning";
var code = Source.newBuilder("enso", """
empty x = 42
""", "TestWarning.enso")
.build();
var v = ctx.eval(code).invokeMember(MethodNames.Module.EVAL_EXPRESSION, "empty").execute(-1);
assertEquals(42, v.asInt());
var option = ensoCtx.findModule(name);
assertTrue("Module found", option.isPresent());
var module = option.get();
var ir = module.getIr().duplicate(true, true, true, true);
var cm = new ModuleCache.CachedModule(ir, CompilationStage.AFTER_CODEGEN, module.getSource());
byte[] arr = module.getCache().serialize(ensoCtx, cm);
var meta = new ModuleCache.Metadata("hash", "code", CompilationStage.AFTER_CODEGEN.toString());
var cachedIr = module.getCache().deserialize(ensoCtx, arr, meta, null);
assertNotNull("IR read", cachedIr);
CompilerTest.assertIR(name, ir, cachedIr.moduleIR());
}
} }

View File

@ -1,22 +1,31 @@
package org.enso.interpreter.runtime; package org.enso.interpreter.runtime;
import static org.junit.Assert.assertTrue;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.logging.Level; import java.util.logging.Level;
import org.enso.compiler.data.BindingsMap;
import org.enso.compiler.data.BindingsMap$ModuleReference$Concrete;
import org.enso.interpreter.runtime.Module;
import static org.enso.interpreter.util.ScalaConversions.nil;
import org.enso.pkg.QualifiedName; import org.enso.pkg.QualifiedName;
import org.enso.polyglot.LanguageInfo; import org.enso.polyglot.LanguageInfo;
import org.enso.polyglot.MethodNames; import org.enso.polyglot.MethodNames;
import org.enso.polyglot.RuntimeOptions; import org.enso.polyglot.RuntimeOptions;
import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Engine; import org.graalvm.polyglot.Engine;
import org.graalvm.polyglot.Source;
import org.graalvm.polyglot.io.IOAccess; import org.graalvm.polyglot.io.IOAccess;
import org.junit.After; import org.junit.After;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import scala.Option;
public class ModuleTest { public class ModuleTest {
private File f; private File f;
@ -60,4 +69,70 @@ public class ModuleTest {
assertTrue( assertTrue(
"getPath is non-null", tFile.getPath() != null && module.getPath() == tFile.getPath()); "getPath is non-null", tFile.getPath() != null && module.getPath() == tFile.getPath());
} }
@Test
public void updaterCanNullTheBindings() throws Exception {
var name = QualifiedName.simpleName("SimpleExample");
var ensoContext =
(EnsoContext)
ctx.getBindings(LanguageInfo.ID)
.invokeMember(MethodNames.TopScope.LEAK_CONTEXT)
.asHostObject();
var tFile = ensoContext.getTruffleFile(f);
var code = Source.newBuilder("enso", """
main = 42
""", name.toString()).build();
ctx.eval(code);
var module = ensoContext.getTopScope().getModule(name.toString()).get().asCompilerModule();
ctx.enter();
var compilerContext = ensoContext.getCompiler().context();
assertNull("No bindings map by default", module.getBindingsMap());
var bindings = new BindingsMap(nil(), new BindingsMap$ModuleReference$Concrete(module));
compilerContext.updateModule(module, (u) -> {
u.bindingsMap(bindings);
});
assertEquals("Bindings map has changed", bindings, module.getBindingsMap());
compilerContext.updateModule(module, (u) -> {
u.bindingsMap(null);
});
assertNull("No bindings map again", module.getBindingsMap());
}
@Test
public void updaterCanNullTheIR() throws Exception {
var name = QualifiedName.simpleName("AnotherSimpleExample");
var ensoContext =
(EnsoContext)
ctx.getBindings(LanguageInfo.ID)
.invokeMember(MethodNames.TopScope.LEAK_CONTEXT)
.asHostObject();
var tFile = ensoContext.getTruffleFile(f);
var code = Source.newBuilder("enso", """
main = 42
""", name.toString()).build();
ctx.eval(code);
var module = ensoContext.getTopScope().getModule(name.toString()).get().asCompilerModule();
ctx.enter();
var compilerContext = ensoContext.getCompiler().context();
assertNull("No IR by default", module.getIr());
var ir = new org.enso.compiler.core.ir.Module(nil(), nil(), nil(), false, Option.empty(), null, null);
compilerContext.updateModule(module, (u) -> {
u.ir(ir);
});
assertEquals("IR has changed", ir, module.getIr());
compilerContext.updateModule(module, (u) -> {
u.ir(null);
});
assertNull("No IR again", module.getIr());
}
} }