mirror of
https://github.com/enso-org/enso.git
synced 2025-01-03 10:51:50 +03:00
Avoid AliasAnalysis for Hello_World.enso (#10996)
This commit is contained in:
parent
7556d8f794
commit
93252ee358
@ -15,6 +15,7 @@ import org.enso.compiler.pass.analyse.BindingAnalysis
|
||||
import org.enso.compiler.pass.resolve.MethodDefinitions
|
||||
import org.enso.persist.Persistance.Reference
|
||||
import org.enso.pkg.QualifiedName
|
||||
import org.enso.editions.LibraryName
|
||||
|
||||
import java.io.ObjectOutputStream
|
||||
import scala.annotation.unused
|
||||
@ -26,8 +27,8 @@ import scala.collection.mutable.ArrayBuffer
|
||||
* @param currentModule the module holding these bindings
|
||||
*/
|
||||
case class BindingsMap(
|
||||
definedEntities: List[DefinedEntity],
|
||||
currentModule: ModuleReference
|
||||
private val _definedEntities: List[DefinedEntity],
|
||||
private var _currentModule: ModuleReference
|
||||
) extends IRPass.IRMetadata {
|
||||
import BindingsMap._
|
||||
|
||||
@ -37,11 +38,38 @@ case class BindingsMap(
|
||||
|
||||
/** Other modules, imported by [[currentModule]].
|
||||
*/
|
||||
var resolvedImports: List[ResolvedImport] = List()
|
||||
private var _resolvedImports: List[ResolvedImport] = List()
|
||||
|
||||
def definedEntities: List[DefinedEntity] = {
|
||||
ensureConvertedToConcrete()
|
||||
_definedEntities
|
||||
}
|
||||
def currentModule: ModuleReference = {
|
||||
ensureConvertedToConcrete()
|
||||
_currentModule
|
||||
}
|
||||
def resolvedImports: List[ResolvedImport] = {
|
||||
ensureConvertedToConcrete()
|
||||
_resolvedImports
|
||||
}
|
||||
def resolvedImports_=(v: List[ResolvedImport]): Unit = {
|
||||
_resolvedImports = v
|
||||
}
|
||||
|
||||
/** Set to non-null after deserialization to signal that conversion to concrete values is needed */
|
||||
private var pendingRepository: PackageRepository = null
|
||||
|
||||
/** Symbols exported by [[currentModule]].
|
||||
*/
|
||||
var exportedSymbols: Map[String, List[ResolvedName]] = Map()
|
||||
private var _exportedSymbols: Map[String, List[ResolvedName]] = Map()
|
||||
|
||||
def exportedSymbols: Map[String, List[ResolvedName]] = {
|
||||
ensureConvertedToConcrete()
|
||||
_exportedSymbols
|
||||
}
|
||||
def exportedSymbols_=(v: Map[String, List[ResolvedName]]): Unit = {
|
||||
_exportedSymbols = v
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
override def prepareForSerialization(
|
||||
@ -54,8 +82,8 @@ case class BindingsMap(
|
||||
override def restoreFromSerialization(
|
||||
compiler: Compiler
|
||||
): Option[BindingsMap] = {
|
||||
val packageRepository = compiler.getPackageRepository
|
||||
this.toConcrete(packageRepository.getModuleMap)
|
||||
this.pendingRepository = compiler.getPackageRepository
|
||||
Some(this)
|
||||
}
|
||||
|
||||
/** Convert this [[BindingsMap]] instance to use abstract module references.
|
||||
@ -63,9 +91,9 @@ case class BindingsMap(
|
||||
* @return `this` with module references converted to abstract
|
||||
*/
|
||||
def toAbstract: BindingsMap = {
|
||||
val copy = this.copy(currentModule = currentModule.toAbstract)
|
||||
copy.resolvedImports = this.resolvedImports.map(_.toAbstract)
|
||||
copy.exportedSymbols = this.exportedSymbols.map { case (key, value) =>
|
||||
val copy = this.copy(_currentModule = _currentModule.toAbstract)
|
||||
copy._resolvedImports = this._resolvedImports.map(_.toAbstract)
|
||||
copy._exportedSymbols = this._exportedSymbols.map { case (key, value) =>
|
||||
key -> value.map(name => name.toAbstract)
|
||||
}
|
||||
copy
|
||||
@ -77,23 +105,51 @@ case class BindingsMap(
|
||||
* instances
|
||||
* @return `this` with module references converted to concrete
|
||||
*/
|
||||
def toConcrete(moduleMap: ModuleMap): Option[BindingsMap] = {
|
||||
val newMap = this.currentModule.toConcrete(moduleMap).map { module =>
|
||||
this.copy(currentModule = module)
|
||||
private def ensureConvertedToConcrete(): Option[BindingsMap] = {
|
||||
val r = pendingRepository
|
||||
if (r != null) {
|
||||
toConcrete(r, r.getModuleMap).map { b =>
|
||||
pendingRepository = null
|
||||
this._currentModule = b._currentModule
|
||||
this._exportedSymbols = b._exportedSymbols
|
||||
this._resolvedImports = b._resolvedImports
|
||||
this
|
||||
}
|
||||
} else {
|
||||
Some(this)
|
||||
}
|
||||
}
|
||||
|
||||
private def toConcrete(
|
||||
r: PackageRepository,
|
||||
moduleMap: ModuleMap
|
||||
): Option[BindingsMap] = {
|
||||
val newMap = this._currentModule
|
||||
.toConcrete(moduleMap)
|
||||
.map { module =>
|
||||
this._currentModule = module
|
||||
this
|
||||
}
|
||||
|
||||
val withImports: Option[BindingsMap] = newMap.flatMap { bindings =>
|
||||
val newImports = this.resolvedImports.map(_.toConcrete(moduleMap))
|
||||
val newImports = this._resolvedImports.map { imp =>
|
||||
imp.targets.foreach { t =>
|
||||
LibraryName
|
||||
.fromModuleName(t.qualifiedName.toString())
|
||||
.foreach(r.ensurePackageIsLoaded(_));
|
||||
}
|
||||
imp.toConcrete(moduleMap)
|
||||
}
|
||||
if (newImports.exists(_.isEmpty)) {
|
||||
None
|
||||
} else {
|
||||
bindings.resolvedImports = newImports.map(_.get)
|
||||
bindings._resolvedImports = newImports.map(_.get)
|
||||
Some(bindings)
|
||||
}
|
||||
}
|
||||
|
||||
val withSymbols: Option[BindingsMap] = withImports.flatMap { bindings =>
|
||||
val newSymbols = this.exportedSymbols.map { case (key, value) =>
|
||||
val newSymbols = this._exportedSymbols.map { case (key, value) =>
|
||||
val newValue = value.map(_.toConcrete(moduleMap))
|
||||
if (newValue.exists(_.isEmpty)) {
|
||||
key -> None
|
||||
@ -105,7 +161,7 @@ case class BindingsMap(
|
||||
if (newSymbols.exists { case (_, v) => v.isEmpty }) {
|
||||
None
|
||||
} else {
|
||||
bindings.exportedSymbols = newSymbols.map { case (k, v) =>
|
||||
bindings._exportedSymbols = newSymbols.map { case (k, v) =>
|
||||
k -> v.get
|
||||
}
|
||||
Some(bindings)
|
||||
|
@ -11,6 +11,7 @@ import org.enso.common.CompilationStage
|
||||
|
||||
import scala.collection.mutable
|
||||
import java.io.IOException
|
||||
import java.util.logging.Level
|
||||
|
||||
/** Runs imports resolution. Starts from a given module and then recursively
|
||||
* collects all modules that are reachable from it.
|
||||
@ -46,7 +47,12 @@ final class ImportResolver(compiler: Compiler) extends ImportResolverForIR {
|
||||
)
|
||||
(ir, currentLocal)
|
||||
} catch {
|
||||
case _: IOException =>
|
||||
case ex: IOException =>
|
||||
context.logSerializationManager(
|
||||
Level.WARNING,
|
||||
"Deserialization of " + module.getName() + " failed",
|
||||
ex
|
||||
)
|
||||
context.updateModule(
|
||||
current,
|
||||
u => {
|
||||
@ -85,6 +91,7 @@ final class ImportResolver(compiler: Compiler) extends ImportResolverForIR {
|
||||
|
||||
currentLocal.resolvedImports =
|
||||
resolvedImports ++ resolvedSyntheticImports
|
||||
|
||||
val newIr = ir.copy(imports = newImportIRs)
|
||||
context.updateModule(
|
||||
current,
|
||||
|
@ -166,7 +166,7 @@ class ExportsResolution(private val context: CompilerContext) {
|
||||
.flatten
|
||||
.distinct
|
||||
|
||||
bindings.exportedSymbols = List(
|
||||
val newSymbols = List(
|
||||
ownEntities,
|
||||
expSymbolsFromResolvedImps
|
||||
).flatten.distinct
|
||||
@ -179,6 +179,7 @@ class ExportsResolution(private val context: CompilerContext) {
|
||||
}
|
||||
(symbolName, resolvedNames)
|
||||
}
|
||||
bindings.exportedSymbols = newSymbols
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,76 @@
|
||||
package org.enso.interpreter.caches;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.enso.common.RuntimeOptions;
|
||||
import org.enso.test.utils.ContextUtils;
|
||||
import org.graalvm.polyglot.Source;
|
||||
import org.junit.Test;
|
||||
|
||||
public class HelloWorldCacheTest {
|
||||
|
||||
@Test
|
||||
public void loadingHelloWorldTwiceUsesCaching() throws Exception {
|
||||
var root = new File("../..").getAbsoluteFile();
|
||||
assertTrue("build.sbt exists at " + root, new File(root, "build.sbt").exists());
|
||||
var helloWorld = children(root, "test", "Benchmarks", "src", "Startup", "Hello_World.enso");
|
||||
assertTrue("Hello_World.enso found", helloWorld.exists());
|
||||
|
||||
// the first run may or may not use caches
|
||||
var firstMsgs = executeOnce(helloWorld);
|
||||
assertTrue("Contains hello world:\n" + firstMsgs, firstMsgs.endsWith("Hello World"));
|
||||
// after the first run the caches for Hello_World.enso must be generated
|
||||
|
||||
// the second run must read Hello_World from its .ir file!
|
||||
var secondMsgs = executeOnce(helloWorld);
|
||||
assertTrue("Contains hello world:\n" + secondMsgs, secondMsgs.contains("Hello World"));
|
||||
assertTrue(
|
||||
"Properly deserialized:\n" + secondMsgs,
|
||||
secondMsgs.contains("Deserializing module Hello_World from IR file: true"));
|
||||
}
|
||||
|
||||
private static String executeOnce(File src) throws Exception {
|
||||
var backLog = new ByteArrayOutputStream();
|
||||
var log = new PrintStream(backLog);
|
||||
|
||||
try (var ctx =
|
||||
ContextUtils.defaultContextBuilder()
|
||||
.out(log)
|
||||
.err(log)
|
||||
.logHandler(log)
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.FINE.getName())
|
||||
.option(RuntimeOptions.DISABLE_IR_CACHES, "false")
|
||||
.option(RuntimeOptions.PROJECT_ROOT, findBenchmarks(src).getAbsolutePath())
|
||||
.build()) {
|
||||
var code = Source.newBuilder("enso", src).build();
|
||||
var res = ContextUtils.evalModule(ctx, code, "main");
|
||||
assertTrue("Result of IO.println is Nothing", res.isNull());
|
||||
}
|
||||
return backLog
|
||||
.toString()
|
||||
.lines()
|
||||
.filter(l -> l.toUpperCase().contains("HELLO"))
|
||||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
private static File children(File f, String... names) {
|
||||
for (var n : names) {
|
||||
f = new File(f, n);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
private static File findBenchmarks(File f) {
|
||||
for (; ; ) {
|
||||
if (f.getName().equals("Benchmarks")) {
|
||||
return f;
|
||||
}
|
||||
f = f.getParentFile();
|
||||
}
|
||||
}
|
||||
}
|
@ -162,7 +162,19 @@ public final class ContextUtils {
|
||||
var b = Source.newBuilder("enso", src, name);
|
||||
s = b.buildLiteral();
|
||||
}
|
||||
var module = ctx.eval(s);
|
||||
return evalModule(ctx, s, methodName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the given source as if it was in a module with given name.
|
||||
*
|
||||
* @param ctx context to evaluate the module at
|
||||
* @param src The source code of the module
|
||||
* @param methodName name of main method to invoke
|
||||
* @return The value returned from the main method of the unnamed module.
|
||||
*/
|
||||
public static Value evalModule(Context ctx, Source src, String methodName) {
|
||||
var module = ctx.eval(src);
|
||||
var assocType = module.invokeMember(Module.GET_ASSOCIATED_TYPE);
|
||||
var method = module.invokeMember(Module.GET_METHOD, assocType, methodName);
|
||||
return "main".equals(methodName) ? method.execute() : method.execute(assocType);
|
||||
|
Loading…
Reference in New Issue
Block a user