mirror of
https://github.com/enso-org/enso.git
synced 2024-12-22 18:38:11 +03:00
Provide names of local variables via FramePointerAnalysis (#10906)
This commit is contained in:
parent
77183e50e9
commit
d37b8f3786
@ -11,8 +11,8 @@ for future goals.
|
||||
|
||||
## Visualization
|
||||
|
||||
The IR can be visualized using `-Denso.compiler.dumpIr` system property. This
|
||||
will output a `.dot` file in [GraphViz](www.graphviz.org) format in the
|
||||
The IR can be visualized using `--vm.D=enso.compiler.dumpIr` system property.
|
||||
This will output a `.dot` file in [GraphViz](www.graphviz.org) format in the
|
||||
`ir-dumps` directory for each IR in the program. The _dot_ file format is a
|
||||
minimal textual format, that can be converted to a graphical representation
|
||||
using the `dot` command from the GraphViz package. For example, on Ubuntu,
|
||||
|
@ -0,0 +1,22 @@
|
||||
package org.enso.compiler.context;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
final class ContextUtils {
|
||||
private ContextUtils() {}
|
||||
|
||||
static <V> V assertSame(String msg, V actual, Supplier<V> expectedSupplier) {
|
||||
assert checkEquality(actual, expectedSupplier)
|
||||
: msg + "\nexpected: " + expectedSupplier.get() + "\nactual: " + actual;
|
||||
return actual;
|
||||
}
|
||||
|
||||
private static <V> boolean checkEquality(V actual, Supplier<V> expectedSupplier) {
|
||||
if (!Objects.equals(expectedSupplier.get(), actual)) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package org.enso.compiler.context;
|
||||
|
||||
/**
|
||||
* A representation of a pointer into a stack frame at a given number of levels above the current.
|
||||
*/
|
||||
public record FramePointer(int parentLevel, int frameSlotIdx) {
|
||||
|
||||
public FramePointer {
|
||||
assert parentLevel >= 0;
|
||||
assert frameSlotIdx >= 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package org.enso.compiler.pass.analyse;
|
||||
|
||||
import org.enso.compiler.core.ir.ProcessingPass;
|
||||
|
||||
public sealed interface FrameAnalysisMeta extends ProcessingPass.Metadata
|
||||
permits FramePointer, FrameVariableNames {}
|
@ -0,0 +1,38 @@
|
||||
package org.enso.compiler.pass.analyse;
|
||||
|
||||
import org.enso.compiler.core.CompilerStub;
|
||||
import org.enso.compiler.core.ir.ProcessingPass;
|
||||
import org.enso.persist.Persistable;
|
||||
import scala.Option;
|
||||
|
||||
/**
|
||||
* A representation of a pointer into a stack frame at a given number of levels above the current.
|
||||
*/
|
||||
@Persistable(clazz = FramePointer.class, id = 1283)
|
||||
public record FramePointer(int parentLevel, int frameSlotIdx) implements FrameAnalysisMeta {
|
||||
|
||||
public FramePointer {
|
||||
assert parentLevel >= 0;
|
||||
assert frameSlotIdx >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metadataName() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessingPass.Metadata prepareForSerialization(CompilerStub compiler) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Option<ProcessingPass.Metadata> restoreFromSerialization(CompilerStub compiler) {
|
||||
return Option.apply(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Option<ProcessingPass.Metadata> duplicate() {
|
||||
return Option.apply(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package org.enso.compiler.pass.analyse;
|
||||
|
||||
import java.util.List;
|
||||
import org.enso.compiler.core.CompilerStub;
|
||||
import org.enso.compiler.core.ir.ProcessingPass;
|
||||
import org.enso.persist.Persistable;
|
||||
import scala.Option;
|
||||
import scala.jdk.javaapi.CollectionConverters;
|
||||
|
||||
@Persistable(id = 1286)
|
||||
public final class FrameVariableNames implements FrameAnalysisMeta {
|
||||
private final List<String> names;
|
||||
|
||||
public FrameVariableNames(List<String> variableNames) {
|
||||
this.names = variableNames;
|
||||
}
|
||||
|
||||
public static FrameVariableNames create(scala.collection.immutable.List<String> names) {
|
||||
return new FrameVariableNames(CollectionConverters.asJava(names));
|
||||
}
|
||||
|
||||
public List<String> variableNames() {
|
||||
return names;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metadataName() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessingPass.Metadata prepareForSerialization(CompilerStub compiler) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Option<ProcessingPass.Metadata> restoreFromSerialization(CompilerStub compiler) {
|
||||
return Option.apply(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Option<ProcessingPass.Metadata> duplicate() {
|
||||
return Option.apply(new FrameVariableNames(names));
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
package org.enso.compiler.pass.analyse;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.enso.compiler.context.FramePointer;
|
||||
import org.enso.compiler.pass.analyse.alias.AliasMetadata;
|
||||
import org.enso.compiler.pass.analyse.alias.graph.Graph;
|
||||
import org.enso.compiler.pass.analyse.alias.graph.GraphOccurrence;
|
||||
@ -67,8 +66,6 @@ import scala.Tuple2$;
|
||||
@Persistable(clazz = Graph.Link.class, id = 1266, allowInlining = false)
|
||||
@Persistable(clazz = TypeInference.class, id = 1280)
|
||||
@Persistable(clazz = FramePointerAnalysis$.class, id = 1281)
|
||||
@Persistable(clazz = FramePointerAnalysis.FramePointerMeta.class, id = 1282)
|
||||
@Persistable(clazz = FramePointer.class, id = 1283)
|
||||
public final class PassPersistance {
|
||||
private PassPersistance() {}
|
||||
|
||||
@ -155,19 +152,16 @@ public final class PassPersistance {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Graph readObject(Input in) throws IOException {
|
||||
var g = new Graph();
|
||||
|
||||
var rootScope = (Graph.Scope) in.readObject();
|
||||
assignParents(rootScope);
|
||||
g.rootScope_$eq(rootScope);
|
||||
|
||||
var links =
|
||||
(scala.collection.immutable.Set) in.readInline(scala.collection.immutable.Set.class);
|
||||
g.initLinks(links);
|
||||
|
||||
var nextIdCounter = in.readInt();
|
||||
g.nextIdCounter_$eq(nextIdCounter);
|
||||
|
||||
var g = new Graph(rootScope, nextIdCounter, links);
|
||||
g.freeze();
|
||||
return g;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
package org.enso.compiler.context
|
||||
|
||||
import org.enso.compiler.pass.analyse.FrameAnalysisMeta
|
||||
import org.enso.compiler.pass.analyse.FramePointer
|
||||
import org.enso.compiler.pass.analyse.FrameVariableNames
|
||||
import org.enso.compiler.pass.analyse.DataflowAnalysis
|
||||
import org.enso.compiler.pass.analyse.alias.graph.{
|
||||
GraphOccurrence,
|
||||
@ -7,6 +10,7 @@ import org.enso.compiler.pass.analyse.alias.graph.{
|
||||
}
|
||||
|
||||
import scala.jdk.CollectionConverters._
|
||||
import java.util.function.BiFunction
|
||||
|
||||
/** A representation of an Enso local scope.
|
||||
*
|
||||
@ -34,12 +38,47 @@ class LocalScope(
|
||||
final val aliasingGraph: () => AliasGraph,
|
||||
final private val scopeProvider: () => AliasGraph.Scope,
|
||||
final private val dataflowInfoProvider: () => DataflowAnalysis.Metadata,
|
||||
final val flattenToParent: Boolean = false,
|
||||
private val parentFrameSlotIdxs: Map[AliasGraph.Id, Int] = Map()
|
||||
final private val symbolsProvider: () => FrameAnalysisMeta = null,
|
||||
final val flattenToParent: Boolean = false,
|
||||
private val parentFrameSlotIdxs: () => Map[AliasGraph.Id, Int] = () => Map()
|
||||
) {
|
||||
lazy val scope: AliasGraph.Scope = scopeProvider()
|
||||
lazy val dataflowInfo: DataflowAnalysis.Metadata = dataflowInfoProvider()
|
||||
|
||||
/** Computes allSymbols needed by this scope. Either the value is obtained
|
||||
* from symbolsProvider or (as a fallback) a computation from aliasingGraph
|
||||
* is performed - the latter situation is logged, when log is not null.
|
||||
*
|
||||
* @param where human "friendly" identification of the caller
|
||||
* @param log function to log or null if no logging is needed
|
||||
*/
|
||||
def allSymbols(
|
||||
where: String,
|
||||
log: BiFunction[String, Array[Object], Void]
|
||||
): java.util.List[String] = {
|
||||
def symbols(): java.util.List[String] = {
|
||||
val r = scope.allDefinitions.map(_.symbol)
|
||||
r.asJava
|
||||
}
|
||||
val meta = if (symbolsProvider == null) null else symbolsProvider()
|
||||
if (meta.isInstanceOf[FrameVariableNames]) {
|
||||
val cached = meta.asInstanceOf[FrameVariableNames].variableNames()
|
||||
if (log != null) {
|
||||
ContextUtils.assertSame(where, cached, () => symbols())
|
||||
}
|
||||
cached
|
||||
} else {
|
||||
val result = symbols()
|
||||
if (log != null) {
|
||||
log(
|
||||
"Scope computed from AliasAnalysis at {0} = {1}",
|
||||
Array(where, result)
|
||||
)
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
private lazy val localFrameSlotIdxs: Map[AliasGraph.Id, Int] =
|
||||
gatherLocalFrameSlotIdxs()
|
||||
|
||||
@ -47,7 +86,7 @@ class LocalScope(
|
||||
* Useful for quick searching for [[FramePointer]] of parent scopes.
|
||||
*/
|
||||
private lazy val allFrameSlotIdxs: Map[AliasGraph.Id, Int] =
|
||||
parentFrameSlotIdxs ++ localFrameSlotIdxs
|
||||
parentFrameSlotIdxs() ++ localFrameSlotIdxs
|
||||
|
||||
/** Creates a new child with a new aliasing scope.
|
||||
*
|
||||
@ -64,15 +103,23 @@ class LocalScope(
|
||||
*/
|
||||
def createChild(
|
||||
childScope: () => AliasGraph.Scope,
|
||||
flattenToParent: Boolean = false
|
||||
flattenToParent: Boolean = false,
|
||||
symbolsProvider: () => FrameVariableNames = null
|
||||
): LocalScope = {
|
||||
val sp = if (flattenToParent) {
|
||||
assert(symbolsProvider == null)
|
||||
this.symbolsProvider
|
||||
} else {
|
||||
symbolsProvider
|
||||
}
|
||||
new LocalScope(
|
||||
Some(this),
|
||||
aliasingGraph,
|
||||
childScope,
|
||||
() => dataflowInfo,
|
||||
sp,
|
||||
flattenToParent,
|
||||
allFrameSlotIdxs
|
||||
() => allFrameSlotIdxs
|
||||
)
|
||||
}
|
||||
|
||||
@ -125,11 +172,27 @@ class LocalScope(
|
||||
}
|
||||
object LocalScope {
|
||||
|
||||
/** Constructs a local scope for an [[EnsoRootNode]].
|
||||
*
|
||||
* @return a defaulted local scope
|
||||
/** Empty and immutable singleton scope.
|
||||
*/
|
||||
def root: LocalScope = {
|
||||
val empty: LocalScope = {
|
||||
val graph = new AliasGraph
|
||||
graph.freeze()
|
||||
val info = DataflowAnalysis.DependencyInfo()
|
||||
val emptyVariableNames = FrameVariableNames.create(List())
|
||||
new LocalScope(
|
||||
None,
|
||||
() => graph,
|
||||
() => graph.rootScope,
|
||||
() => info,
|
||||
() => emptyVariableNames
|
||||
)
|
||||
}
|
||||
|
||||
/** Constructs a new local scope for an [[EnsoRootNode]] that can then be modified.
|
||||
*
|
||||
* @return a new empty scope ready for additional modifications.
|
||||
*/
|
||||
def createEmpty: LocalScope = {
|
||||
val graph = new AliasGraph
|
||||
val info = DataflowAnalysis.DependencyInfo()
|
||||
new LocalScope(
|
||||
|
@ -1,12 +1,7 @@
|
||||
package org.enso.compiler.pass.analyse
|
||||
|
||||
import org.enso.compiler.context.{
|
||||
CompilerContext,
|
||||
FramePointer,
|
||||
InlineContext,
|
||||
LocalScope,
|
||||
ModuleContext
|
||||
}
|
||||
import org.enso.compiler.pass.analyse.FramePointer
|
||||
import org.enso.compiler.context.{InlineContext, LocalScope, ModuleContext}
|
||||
import org.enso.compiler.core.ir.Name.GenericAnnotation
|
||||
import org.enso.compiler.core.{CompilerError, IR}
|
||||
import org.enso.compiler.core.ir.expression.{Application, Case}
|
||||
@ -17,13 +12,11 @@ import org.enso.compiler.core.ir.{
|
||||
Function,
|
||||
Module,
|
||||
Name,
|
||||
Pattern,
|
||||
ProcessingPass
|
||||
Pattern
|
||||
}
|
||||
import org.enso.compiler.core.ir.module.scope.Definition
|
||||
import org.enso.compiler.core.ir.module.scope.definition.Method
|
||||
import org.enso.compiler.pass.IRPass
|
||||
import org.enso.compiler.pass.IRPass.IRMetadata
|
||||
import org.enso.compiler.pass.analyse.alias.AliasMetadata
|
||||
import org.enso.compiler.pass.analyse.alias.graph.{Graph, GraphOccurrence}
|
||||
|
||||
@ -33,7 +26,7 @@ import org.enso.compiler.pass.analyse.alias.graph.{Graph, GraphOccurrence}
|
||||
*/
|
||||
case object FramePointerAnalysis extends IRPass {
|
||||
|
||||
override type Metadata = FramePointerMeta
|
||||
override type Metadata = FrameAnalysisMeta
|
||||
|
||||
override type Config = IRPass.Configuration.Default
|
||||
|
||||
@ -54,14 +47,18 @@ case object FramePointerAnalysis extends IRPass {
|
||||
ir match {
|
||||
case m: Method.Explicit =>
|
||||
getAliasAnalysisGraph(m) match {
|
||||
case Some(graph) =>
|
||||
case Some(
|
||||
graph
|
||||
) =>
|
||||
processExpression(m.body, graph)
|
||||
updateSymbolNames(m, graph.rootScope)
|
||||
case _ => ()
|
||||
}
|
||||
case m: Method.Conversion =>
|
||||
getAliasAnalysisGraph(m) match {
|
||||
case Some(graph) =>
|
||||
processExpression(m.body, graph)
|
||||
updateSymbolNames(m, graph.rootScope)
|
||||
case _ => ()
|
||||
}
|
||||
case t: Definition.Type =>
|
||||
@ -78,7 +75,9 @@ case object FramePointerAnalysis extends IRPass {
|
||||
member.annotations.foreach { annotation =>
|
||||
processAnnotation(annotation, memberGraph)
|
||||
}
|
||||
updateSymbolNames(member, memberGraph.rootScope)
|
||||
}
|
||||
updateSymbolNames(t, graph.rootScope)
|
||||
case _ => ()
|
||||
}
|
||||
case annot: GenericAnnotation =>
|
||||
@ -94,6 +93,11 @@ case object FramePointerAnalysis extends IRPass {
|
||||
}
|
||||
}
|
||||
|
||||
private def updateSymbolNames(e: IR, s: Graph.Scope): Unit = {
|
||||
val symbols = s.allDefinitions.map(_.symbol)
|
||||
updateMeta(e, FrameVariableNames.create(symbols))
|
||||
}
|
||||
|
||||
private def processAnnotation(
|
||||
annot: GenericAnnotation,
|
||||
graph: Graph
|
||||
@ -103,6 +107,7 @@ case object FramePointerAnalysis extends IRPass {
|
||||
rootScope.graph
|
||||
case None => graph
|
||||
}
|
||||
updateSymbolNames(annot, annotGraph.rootScope)
|
||||
processExpression(annot.expression, annotGraph)
|
||||
}
|
||||
|
||||
@ -123,7 +128,8 @@ case object FramePointerAnalysis extends IRPass {
|
||||
case Some(defaultValue) =>
|
||||
getAliasAnalysisGraph(defaultValue) match {
|
||||
case Some(defaultValueGraph) =>
|
||||
processExpression(defaultValue, defaultValueGraph)
|
||||
processExpression(defaultValue, defaultValueGraph, false)
|
||||
maybAttachFrameVariableNames(defaultValue)
|
||||
case None =>
|
||||
processExpression(defaultValue, graph)
|
||||
}
|
||||
@ -134,7 +140,8 @@ case object FramePointerAnalysis extends IRPass {
|
||||
|
||||
private def processExpression(
|
||||
exprIr: Expression,
|
||||
graph: Graph
|
||||
graph: Graph,
|
||||
updateSymbols: Boolean = true
|
||||
): Unit = {
|
||||
exprIr match {
|
||||
case name: Name => maybeAttachFramePointer(name, graph)
|
||||
@ -147,7 +154,6 @@ case object FramePointerAnalysis extends IRPass {
|
||||
processArgumentDefs(args, graph)
|
||||
processExpression(body, graph)
|
||||
case binding @ Expression.Binding(name, expr, _, _) =>
|
||||
maybeAttachFramePointer(binding, graph)
|
||||
maybeAttachFramePointer(name, graph)
|
||||
processExpression(expr, graph)
|
||||
maybeAttachFramePointer(binding, graph)
|
||||
@ -159,6 +165,9 @@ case object FramePointerAnalysis extends IRPass {
|
||||
}
|
||||
case _ => ()
|
||||
}
|
||||
if (updateSymbols) {
|
||||
maybAttachFrameVariableNames(exprIr)
|
||||
}
|
||||
}
|
||||
|
||||
private def processCaseBranch(
|
||||
@ -170,6 +179,7 @@ case object FramePointerAnalysis extends IRPass {
|
||||
"An alias analysis graph is expected on " + branch
|
||||
)
|
||||
case Some(graph) =>
|
||||
maybAttachFrameVariableNames(branch)
|
||||
processExpression(branch.expression, graph)
|
||||
processCasePattern(branch.pattern, graph)
|
||||
}
|
||||
@ -197,6 +207,7 @@ case object FramePointerAnalysis extends IRPass {
|
||||
case _: Pattern.Documentation => ()
|
||||
case _ => ()
|
||||
}
|
||||
updateSymbolNames(pattern, graph.rootScope)
|
||||
}
|
||||
|
||||
private def processApplication(
|
||||
@ -230,10 +241,19 @@ case object FramePointerAnalysis extends IRPass {
|
||||
arguments.foreach { case arg @ CallArgument.Specified(name, value, _, _) =>
|
||||
maybeAttachFramePointer(arg, graph)
|
||||
name.foreach(maybeAttachFramePointer(_, graph))
|
||||
processExpression(value, graph)
|
||||
processExpression(value, graph, false)
|
||||
maybAttachFrameVariableNames(value)
|
||||
maybAttachFrameVariableNames(arg)
|
||||
}
|
||||
}
|
||||
|
||||
private def maybAttachFrameVariableNames(ir: IR): Unit = {
|
||||
getAliasRootScope(ir).foreach(root =>
|
||||
updateSymbolNames(ir, root.graph.rootScope)
|
||||
)
|
||||
getAliasChildScope(ir).foreach(child => updateSymbolNames(ir, child.scope))
|
||||
}
|
||||
|
||||
/** Attaches [[FramePointerMeta]] metadata to the given `ir` if there is an
|
||||
* appropriate [[AliasMetadata.Occurrence]] already attached to it.
|
||||
* @param ir IR to attach the frame pointer metadata to.
|
||||
@ -263,7 +283,10 @@ case object FramePointerAnalysis extends IRPass {
|
||||
val parentLevel = getScopeDistance(defScope, scope)
|
||||
val frameSlotIdx =
|
||||
getFrameSlotIdxInScope(graph, defScope, defOcc)
|
||||
updateMeta(ir, new FramePointer(parentLevel, frameSlotIdx))
|
||||
updateMeta(
|
||||
ir,
|
||||
new FramePointer(parentLevel, frameSlotIdx)
|
||||
)
|
||||
case None =>
|
||||
// It is possible that there is no Def for this Use. It can, for example, be
|
||||
// Use for some global symbol. In `IrToTruffle`, an UnresolvedSymbol will be
|
||||
@ -275,7 +298,10 @@ case object FramePointerAnalysis extends IRPass {
|
||||
// The definition cannot write to parent's frame slots.
|
||||
val parentLevel = 0
|
||||
val frameSlotIdx = getFrameSlotIdxInScope(graph, scope, defn)
|
||||
updateMeta(ir, new FramePointer(parentLevel, frameSlotIdx))
|
||||
updateMeta(
|
||||
ir,
|
||||
new FramePointer(parentLevel, frameSlotIdx)
|
||||
)
|
||||
case _ => ()
|
||||
}
|
||||
case _ => ()
|
||||
@ -286,9 +312,19 @@ case object FramePointerAnalysis extends IRPass {
|
||||
|
||||
private def updateMeta(
|
||||
ir: IR,
|
||||
framePointer: FramePointer
|
||||
newMeta: FrameAnalysisMeta
|
||||
): Unit = {
|
||||
ir.passData().update(this, new FramePointerMeta(framePointer))
|
||||
ir.passData().get(this) match {
|
||||
case None =>
|
||||
ir.passData()
|
||||
.update(this, newMeta)
|
||||
case Some(meta) =>
|
||||
val ex = new IllegalStateException(
|
||||
"Unexpected FrameAnalysisMeta associated with IR " + ir + "\nOld: " + meta + " new " + newMeta
|
||||
)
|
||||
ex.setStackTrace(ex.getStackTrace().slice(0, 10))
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the index of the given `defOcc` definition in the given `scope`
|
||||
@ -357,6 +393,15 @@ case object FramePointerAnalysis extends IRPass {
|
||||
}
|
||||
}
|
||||
|
||||
private def getAliasChildScope(
|
||||
ir: IR
|
||||
): Option[AliasMetadata.ChildScope] = {
|
||||
ir.passData()
|
||||
.get(AliasAnalysis)
|
||||
.filter(_.isInstanceOf[AliasMetadata.ChildScope])
|
||||
.map(_.asInstanceOf[AliasMetadata.ChildScope])
|
||||
}
|
||||
|
||||
private def getAliasAnalysisGraph(
|
||||
ir: IR
|
||||
): Option[Graph] = {
|
||||
@ -380,36 +425,4 @@ case object FramePointerAnalysis extends IRPass {
|
||||
exprIr
|
||||
}
|
||||
}
|
||||
|
||||
// === Pass Configuration ===================================================
|
||||
|
||||
class FramePointerMeta(
|
||||
val framePointer: FramePointer
|
||||
) extends IRMetadata {
|
||||
override val metadataName: String = "FramePointer"
|
||||
|
||||
def parentLevel(): Int = framePointer.parentLevel
|
||||
|
||||
def frameSlotIdx(): Int = framePointer.frameSlotIdx
|
||||
|
||||
/** @inheritdoc
|
||||
*/
|
||||
override def duplicate(): Option[Metadata] = {
|
||||
Some(new FramePointerMeta(framePointer))
|
||||
}
|
||||
|
||||
/** @inheritdoc
|
||||
*/
|
||||
override def prepareForSerialization(
|
||||
compiler: CompilerContext
|
||||
): ProcessingPass.Metadata = this
|
||||
|
||||
/** @inheritdoc
|
||||
*/
|
||||
override def restoreFromSerialization(
|
||||
compiler: CompilerContext
|
||||
): Option[ProcessingPass.Metadata] = Some(this)
|
||||
|
||||
override def toString: String = s"FramePointerMeta($framePointer)"
|
||||
}
|
||||
}
|
||||
|
@ -9,44 +9,53 @@ import scala.collection.mutable
|
||||
import scala.reflect.ClassTag
|
||||
|
||||
/** A graph containing aliasing information for a given root scope in Enso. */
|
||||
sealed class Graph extends Serializable {
|
||||
var rootScope: Graph.Scope = new Graph.Scope()
|
||||
private var links: Set[Graph.Link] = Set()
|
||||
sealed class Graph(
|
||||
val rootScope: Graph.Scope = new Graph.Scope(),
|
||||
private var _nextIdCounter: Int = 0,
|
||||
private var links: Set[Graph.Link] = Set()
|
||||
) extends Serializable {
|
||||
private var sourceLinks: Map[Graph.Id, Set[Graph.Link]] = new HashMap()
|
||||
private var targetLinks: Map[Graph.Id, Set[Graph.Link]] = new HashMap()
|
||||
var nextIdCounter = 0
|
||||
private var frozen: Boolean = false
|
||||
|
||||
{
|
||||
links.foreach(addSourceTargetLink)
|
||||
}
|
||||
|
||||
private var globalSymbols: Map[Graph.Symbol, GraphOccurrence.Global] =
|
||||
Map()
|
||||
|
||||
/** @return the next counter value
|
||||
*/
|
||||
def nextIdCounter: Int = _nextIdCounter
|
||||
|
||||
/** @return a deep structural copy of `this` */
|
||||
def deepCopy(
|
||||
scope_mapping: mutable.Map[Scope, Scope] = mutable.Map()
|
||||
): Graph = {
|
||||
val copy = new Graph
|
||||
copy.rootScope = this.rootScope.deepCopy(scope_mapping)
|
||||
val copy = new Graph(
|
||||
this.rootScope.deepCopy(scope_mapping),
|
||||
this.nextIdCounter
|
||||
)
|
||||
copy.links = this.links
|
||||
copy.sourceLinks = this.sourceLinks
|
||||
copy.targetLinks = this.targetLinks
|
||||
copy.globalSymbols = this.globalSymbols
|
||||
copy.nextIdCounter = this.nextIdCounter
|
||||
copy
|
||||
}
|
||||
|
||||
def initLinks(links: Set[Graph.Link]): Unit = {
|
||||
sourceLinks = new HashMap()
|
||||
targetLinks = new HashMap()
|
||||
links.foreach(addSourceTargetLink)
|
||||
this.links = links
|
||||
}
|
||||
|
||||
def getLinks(): Set[Graph.Link] = links
|
||||
|
||||
def freeze(): Unit = {
|
||||
frozen = true
|
||||
}
|
||||
|
||||
/** Registers a requested global symbol in the aliasing scope.
|
||||
*
|
||||
* @param sym the symbol occurrence
|
||||
*/
|
||||
def addGlobalSymbol(sym: GraphOccurrence.Global): Unit = {
|
||||
assert(!frozen)
|
||||
if (!globalSymbols.contains(sym.symbol)) {
|
||||
globalSymbols = globalSymbols + (sym.symbol -> sym)
|
||||
}
|
||||
@ -57,12 +66,13 @@ sealed class Graph extends Serializable {
|
||||
* @return a copy of the graph structure
|
||||
*/
|
||||
def copy: Graph = {
|
||||
val graph = new Graph
|
||||
graph.links = links
|
||||
graph.sourceLinks = sourceLinks
|
||||
graph.targetLinks = targetLinks
|
||||
graph.rootScope = rootScope.deepCopy(mutable.Map())
|
||||
graph.nextIdCounter = nextIdCounter
|
||||
val graph = new Graph(
|
||||
rootScope.deepCopy(mutable.Map()),
|
||||
nextIdCounter
|
||||
)
|
||||
graph.links = links
|
||||
graph.sourceLinks = sourceLinks
|
||||
graph.targetLinks = targetLinks
|
||||
|
||||
graph
|
||||
}
|
||||
@ -84,8 +94,8 @@ sealed class Graph extends Serializable {
|
||||
* @return a unique identifier for this graph
|
||||
*/
|
||||
def nextId(): Graph.Id = {
|
||||
val nextId = nextIdCounter
|
||||
nextIdCounter += 1
|
||||
val nextId = _nextIdCounter
|
||||
_nextIdCounter += 1
|
||||
nextId
|
||||
}
|
||||
|
||||
@ -99,13 +109,14 @@ sealed class Graph extends Serializable {
|
||||
occurrence: GraphOccurrence.Use
|
||||
): Option[Graph.Link] = {
|
||||
scopeFor(occurrence.id).flatMap(_.resolveUsage(occurrence).map { link =>
|
||||
links += link
|
||||
addSourceTargetLink(link)
|
||||
links += link
|
||||
link
|
||||
})
|
||||
}
|
||||
|
||||
private def addSourceTargetLink(link: Graph.Link): Unit = {
|
||||
assert(!frozen)
|
||||
sourceLinks = sourceLinks.updatedWith(link.source)(v =>
|
||||
v.map(s => s + link).orElse(Some(Set(link)))
|
||||
)
|
||||
|
@ -488,7 +488,7 @@ class ChangesetBuilderTest
|
||||
|
||||
def freshInlineContext: InlineContext =
|
||||
buildInlineContext(
|
||||
localScope = Some(LocalScope.root),
|
||||
localScope = Some(LocalScope.createEmpty),
|
||||
freshNameSupply = Some(new FreshNameSupply),
|
||||
isInTailPosition = Some(false)
|
||||
)
|
||||
|
@ -30,7 +30,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import org.enso.common.DebugServerInfo;
|
||||
import org.enso.compiler.context.FramePointer;
|
||||
import org.enso.compiler.pass.analyse.FramePointer;
|
||||
import org.enso.interpreter.node.EnsoRootNode;
|
||||
import org.enso.interpreter.node.expression.builtin.debug.DebugBreakpointNode;
|
||||
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
|
||||
|
@ -442,6 +442,48 @@ public class ExecCompilerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFnAsADefaultValue() throws Exception {
|
||||
var code =
|
||||
"""
|
||||
type N
|
||||
type T
|
||||
V (r:(T -> N | T)=(_->N))
|
||||
|
||||
v self = self.r self
|
||||
|
||||
run type = case type of
|
||||
0 -> T.V
|
||||
1 -> T.V (_->N)
|
||||
""";
|
||||
var module = ctx.eval(LanguageInfo.ID, code);
|
||||
var run = module.invokeMember("eval_expression", "run");
|
||||
var real = run.execute(1L);
|
||||
var realN = real.invokeMember("v");
|
||||
var defaulted = run.execute(0L);
|
||||
var defaultedN = defaulted.invokeMember("v");
|
||||
assertEquals("Should be the same", realN, defaultedN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTemporaryFileSpecProblem() throws Exception {
|
||||
var code =
|
||||
"""
|
||||
from Standard.Base.Errors.Common import all
|
||||
|
||||
run t = F.app f->
|
||||
f.read t
|
||||
|
||||
type F
|
||||
read self r = r
|
||||
app fn = fn F
|
||||
""";
|
||||
var module = ctx.eval(LanguageInfo.ID, code);
|
||||
var run = module.invokeMember("eval_expression", "run");
|
||||
var real = run.execute(1L);
|
||||
assertEquals("Should be the same", 1, real.asInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertlyIdentifyNameOfJavaClassInError() throws Exception {
|
||||
var module =
|
||||
|
@ -161,7 +161,7 @@ class DataflowAnalysisTest extends CompilerTest {
|
||||
*/
|
||||
def mkInlineContext: InlineContext = {
|
||||
buildInlineContext(
|
||||
localScope = Some(LocalScope.root),
|
||||
localScope = Some(LocalScope.createEmpty),
|
||||
isInTailPosition = Some(false),
|
||||
freshNameSupply = Some(new FreshNameSupply)
|
||||
)
|
||||
|
@ -71,7 +71,7 @@ class DemandAnalysisTest extends CompilerTest {
|
||||
*/
|
||||
def mkInlineContext: InlineContext = {
|
||||
buildInlineContext(
|
||||
localScope = Some(LocalScope.root),
|
||||
localScope = Some(LocalScope.createEmpty),
|
||||
freshNameSupply = Some(new FreshNameSupply)
|
||||
)
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package org.enso.compiler.test.pass.analyse
|
||||
|
||||
import org.enso.compiler.Passes
|
||||
import org.enso.compiler.context.{FramePointer, FreshNameSupply, ModuleContext}
|
||||
import org.enso.compiler.pass.analyse.FramePointer
|
||||
import org.enso.compiler.pass.analyse.FrameAnalysisMeta
|
||||
import org.enso.compiler.context.{FreshNameSupply, ModuleContext}
|
||||
import org.enso.compiler.core.IR
|
||||
import org.enso.compiler.core.ir.{
|
||||
CallArgument,
|
||||
@ -87,10 +89,10 @@ class FramePointerAnalysisTest extends CompilerTest {
|
||||
withClue("Expression.Binding must have FramePointer associated") {
|
||||
allOcc.head._1
|
||||
.unsafeGetMetadata(FramePointerAnalysis, "should exist")
|
||||
.framePointer shouldEqual new FramePointer(0, 1)
|
||||
.asInstanceOf[FramePointer] shouldEqual new FramePointer(0, 1)
|
||||
allOcc.last._1
|
||||
.unsafeGetMetadata(FramePointerAnalysis, "should exist")
|
||||
.framePointer shouldEqual new FramePointer(0, 2)
|
||||
.asInstanceOf[FramePointer] shouldEqual new FramePointer(0, 2)
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,7 +131,7 @@ class FramePointerAnalysisTest extends CompilerTest {
|
||||
"There should be no associated FramePointer with usage of `+`, because it is not defined " +
|
||||
"in any scope"
|
||||
) {
|
||||
plusUseIr.passData().get(FramePointerAnalysis) shouldNot be(defined)
|
||||
findFP(plusUseIr) shouldNot be(defined)
|
||||
}
|
||||
val framePointers = collectAllFramePointers(ir)
|
||||
framePointers.size shouldBe 4
|
||||
@ -429,7 +431,7 @@ class FramePointerAnalysisTest extends CompilerTest {
|
||||
lit => lit.name == "My_Type"
|
||||
).last
|
||||
withClue("No frame pointer attached to a symbol with global occurence") {
|
||||
myTypeLit.passData.get(FramePointerAnalysis) shouldNot be(defined)
|
||||
findFP(myTypeLit) shouldNot be(defined)
|
||||
}
|
||||
withClue("There is a Use occurence") {
|
||||
myTypeLit.passData.get(AliasAnalysis) shouldBe defined
|
||||
@ -455,7 +457,7 @@ class FramePointerAnalysisTest extends CompilerTest {
|
||||
lit => lit.name == "My_Type"
|
||||
).apply(1)
|
||||
withClue("No frame pointer attached to a symbol with global occurence") {
|
||||
myTypeLit.passData.get(FramePointerAnalysis) shouldNot be(defined)
|
||||
findFP(myTypeLit) shouldNot be(defined)
|
||||
}
|
||||
withClue("There is a Use occurence") {
|
||||
myTypeLit.passData.get(AliasAnalysis) shouldBe defined
|
||||
@ -466,6 +468,10 @@ class FramePointerAnalysisTest extends CompilerTest {
|
||||
}
|
||||
}
|
||||
|
||||
private def findFP(ir: IR) = ir.passData
|
||||
.get(FramePointerAnalysis)
|
||||
.filter(meta => meta.isInstanceOf[FramePointer])
|
||||
|
||||
/** Find the first IR element of the given `T` type by the given `filterCondition`.
|
||||
* @param filterCondition Filter condition will be applied to all the elements of the desired type.
|
||||
* The first element that matches the condition will be returned
|
||||
@ -513,7 +519,7 @@ class FramePointerAnalysisTest extends CompilerTest {
|
||||
}
|
||||
ir
|
||||
.unsafeGetMetadata(FramePointerAnalysis, "should exist")
|
||||
.framePointer shouldEqual framePointer
|
||||
.asInstanceOf[FramePointer] shouldEqual framePointer
|
||||
}
|
||||
|
||||
private def findAssociatedIr(
|
||||
@ -548,10 +554,11 @@ class FramePointerAnalysisTest extends CompilerTest {
|
||||
|
||||
private def collectAllFramePointers(
|
||||
ir: IR
|
||||
): List[(IR, FramePointerAnalysis.Metadata)] = {
|
||||
): List[(IR, FrameAnalysisMeta)] = {
|
||||
ir.preorder().flatMap { childIr =>
|
||||
childIr.getMetadata(FramePointerAnalysis) match {
|
||||
case Some(framePointerMeta: FramePointerAnalysis.Metadata) =>
|
||||
case Some(framePointerMeta: FrameAnalysisMeta)
|
||||
if (framePointerMeta.isInstanceOf[FramePointer]) =>
|
||||
Some((childIr, framePointerMeta))
|
||||
case _ => None
|
||||
}
|
||||
|
@ -31,14 +31,14 @@ class TailCallTest extends CompilerTest {
|
||||
|
||||
def mkTailContext: InlineContext =
|
||||
buildInlineContext(
|
||||
localScope = Some(LocalScope.root),
|
||||
localScope = Some(LocalScope.createEmpty),
|
||||
isInTailPosition = Some(true),
|
||||
freshNameSupply = Some(new FreshNameSupply)
|
||||
)
|
||||
|
||||
def mkNoTailContext: InlineContext =
|
||||
buildInlineContext(
|
||||
localScope = Some(LocalScope.root),
|
||||
localScope = Some(LocalScope.createEmpty),
|
||||
isInTailPosition = Some(false),
|
||||
freshNameSupply = Some(new FreshNameSupply)
|
||||
)
|
||||
|
@ -51,7 +51,7 @@ class UnusedBindingsTest extends CompilerTest with Inside {
|
||||
*/
|
||||
def mkInlineContext: InlineContext = {
|
||||
buildInlineContext(
|
||||
localScope = Some(LocalScope.root),
|
||||
localScope = Some(LocalScope.createEmpty),
|
||||
isInTailPosition = Some(false),
|
||||
freshNameSupply = Some(new FreshNameSupply)
|
||||
)
|
||||
|
@ -77,7 +77,7 @@ class LambdaConsolidateTest extends CompilerTest {
|
||||
*/
|
||||
def mkContext: InlineContext = {
|
||||
buildInlineContext(
|
||||
localScope = Some(LocalScope.root),
|
||||
localScope = Some(LocalScope.createEmpty),
|
||||
freshNameSupply = Some(new FreshNameSupply),
|
||||
passConfiguration = Some(passConfiguration)
|
||||
)
|
||||
|
@ -80,7 +80,7 @@ class SuspendedArgumentsTest extends CompilerTest {
|
||||
def mkInlineContext: InlineContext = {
|
||||
buildInlineContext(
|
||||
freshNameSupply = Some(new FreshNameSupply),
|
||||
localScope = Some(LocalScope.root)
|
||||
localScope = Some(LocalScope.createEmpty)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,7 @@ object Function {
|
||||
Persistance.Reference.of(body, true),
|
||||
location,
|
||||
true,
|
||||
ir.passData
|
||||
ir.passData.duplicate()
|
||||
)
|
||||
diagnostics = ir.diagnostics
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ public final class EnsoLanguage extends TruffleLanguage<EnsoContext> {
|
||||
if (optionTupple.nonEmpty()) {
|
||||
var newInlineContext = optionTupple.get()._1();
|
||||
var ir = optionTupple.get()._2();
|
||||
var sco = newInlineContext.localScope().getOrElse(LocalScope::root);
|
||||
var sco = newInlineContext.localScope().getOrElse(LocalScope::empty);
|
||||
var mod = newInlineContext.getModule();
|
||||
var m = org.enso.interpreter.runtime.Module.fromCompilerModule(mod);
|
||||
var toTruffle =
|
||||
|
@ -287,7 +287,11 @@ public final class Cache<T, M> {
|
||||
return Optional.empty();
|
||||
}
|
||||
} catch (ClassNotFoundException | IOException ex) {
|
||||
logger.log(Level.WARNING, "`" + logName + "` in " + dataPath + " failed to load: ", ex);
|
||||
logger.log(
|
||||
Level.WARNING,
|
||||
"`{0}` in {1} failed to load: {2}",
|
||||
new Object[] {logName, dataPath, ex.getMessage()});
|
||||
logger.log(Level.FINE, "`{0}` in {1} failed to load:", ex);
|
||||
invalidateCache(cacheRoot, logger);
|
||||
return Optional.empty();
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.enso.interpreter.node;
|
||||
|
||||
import com.oracle.truffle.api.TruffleLogger;
|
||||
import com.oracle.truffle.api.frame.FrameDescriptor;
|
||||
import com.oracle.truffle.api.frame.FrameSlotKind;
|
||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
@ -7,16 +8,20 @@ import com.oracle.truffle.api.nodes.RootNode;
|
||||
import com.oracle.truffle.api.source.Source;
|
||||
import com.oracle.truffle.api.source.SourceSection;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.logging.Level;
|
||||
import org.enso.common.LanguageInfo;
|
||||
import org.enso.compiler.context.LocalScope;
|
||||
import org.enso.interpreter.EnsoLanguage;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.error.DataflowError;
|
||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||
import org.enso.interpreter.util.ScalaConversions;
|
||||
|
||||
/** A common base class for all kinds of root node in Enso. */
|
||||
@NodeInfo(shortName = "Root", description = "A root node for Enso computations")
|
||||
public abstract class EnsoRootNode extends RootNode {
|
||||
private static final TruffleLogger LOGGER = TruffleLogger.getLogger(LanguageInfo.ID);
|
||||
|
||||
private final String name;
|
||||
private final int sourceStartIndex;
|
||||
private final int sourceLength;
|
||||
@ -39,7 +44,7 @@ public abstract class EnsoRootNode extends RootNode {
|
||||
ModuleScope moduleScope,
|
||||
String name,
|
||||
SourceSection sourceSection) {
|
||||
super(language, buildFrameDescriptor(localScope));
|
||||
super(language, buildFrameDescriptor(name, localScope, LOGGER));
|
||||
Objects.requireNonNull(language);
|
||||
Objects.requireNonNull(localScope);
|
||||
Objects.requireNonNull(moduleScope);
|
||||
@ -62,11 +67,21 @@ public abstract class EnsoRootNode extends RootNode {
|
||||
*
|
||||
* @return {@link FrameDescriptor} built from the variable definitions in the local localScope.
|
||||
*/
|
||||
private static FrameDescriptor buildFrameDescriptor(LocalScope localScope) {
|
||||
private static FrameDescriptor buildFrameDescriptor(
|
||||
String name, LocalScope localScope, TruffleLogger log) {
|
||||
var descriptorBuilder = FrameDescriptor.newBuilder();
|
||||
descriptorBuilder.addSlot(FrameSlotKind.Object, LocalScope.monadicStateSlotName(), null);
|
||||
for (var definition : ScalaConversions.asJava(localScope.scope().allDefinitions())) {
|
||||
descriptorBuilder.addSlot(FrameSlotKind.Illegal, definition.symbol(), null);
|
||||
|
||||
BiFunction<String, Object[], Void> logFnOrNull =
|
||||
log.isLoggable(Level.FINE)
|
||||
? (msg, args) -> {
|
||||
log.log(Level.FINE, msg, args);
|
||||
return null;
|
||||
}
|
||||
: null;
|
||||
var allDefs = localScope.allSymbols(name, logFnOrNull);
|
||||
for (var definition : allDefs) {
|
||||
descriptorBuilder.addSlot(FrameSlotKind.Illegal, definition, null);
|
||||
}
|
||||
descriptorBuilder.defaultValue(DataflowError.UNINITIALIZED);
|
||||
var frameDescriptor = descriptorBuilder.build();
|
||||
|
@ -65,7 +65,8 @@ public abstract class EvalNode extends BaseNode {
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
RootCallTarget parseExpression(LocalScope scope, ModuleScope moduleScope, String expression) {
|
||||
EnsoContext context = EnsoContext.get(this);
|
||||
LocalScope localScope = scope.createChild();
|
||||
LocalScope localScope =
|
||||
scope == LocalScope.empty() ? LocalScope.createEmpty() : scope.createChild();
|
||||
var compiler = context.getCompiler();
|
||||
InlineContext inlineContext =
|
||||
InlineContext.fromJava(
|
||||
@ -83,7 +84,7 @@ public abstract class EvalNode extends BaseNode {
|
||||
var newInlineContext = tuppleOption.get()._1();
|
||||
var ir = tuppleOption.get()._2();
|
||||
|
||||
var sco = newInlineContext.localScope().getOrElse(LocalScope::root);
|
||||
var sco = newInlineContext.localScope().getOrElse(LocalScope::empty);
|
||||
var mod = newInlineContext.getModule();
|
||||
var m = org.enso.interpreter.runtime.Module.fromCompilerModule(mod);
|
||||
var toTruffle = new IrToTruffle(context, src, m.getScopeBuilder(), compiler.getConfig());
|
||||
|
@ -8,7 +8,7 @@ import com.oracle.truffle.api.frame.MaterializedFrame;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
import org.enso.compiler.context.FramePointer;
|
||||
import org.enso.compiler.pass.analyse.FramePointer;
|
||||
import org.enso.interpreter.node.ExpressionNode;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
|
||||
|
@ -660,7 +660,7 @@ public final class Module implements EnsoObject {
|
||||
.getBuiltinFunction(
|
||||
builtins.debug(), Builtins.MethodNames.Debug.EVAL, context.getLanguage())
|
||||
.orElseThrow();
|
||||
CallerInfo callerInfo = new CallerInfo(null, LocalScope.root(), scope);
|
||||
CallerInfo callerInfo = new CallerInfo(null, LocalScope.empty(), scope);
|
||||
return callOptimiserNode.executeDispatch(
|
||||
null,
|
||||
eval.getFunction(),
|
||||
|
@ -200,7 +200,7 @@ public final class UnresolvedConstructor implements EnsoObject {
|
||||
body.adoptChildren();
|
||||
var root =
|
||||
ClosureRootNode.build(
|
||||
lang, LocalScope.root(), scope, body, section, prototype.getName(), true, true);
|
||||
lang, LocalScope.empty(), scope, body, section, prototype.getName(), true, true);
|
||||
root.adoptChildren();
|
||||
assert Objects.equals(expr.getSourceSection(), section)
|
||||
: "Expr: " + expr.getSourceSection() + " orig: " + section;
|
||||
|
@ -112,7 +112,7 @@ public final class AtomConstructor implements EnsoObject {
|
||||
return initializeFields(
|
||||
language,
|
||||
null,
|
||||
LocalScope.root(),
|
||||
LocalScope.empty(),
|
||||
scopeBuilder,
|
||||
new ExpressionNode[0],
|
||||
reads,
|
||||
|
@ -24,7 +24,7 @@ final class GetFieldNode extends EnsoRootNode {
|
||||
* @param index the index this node should use for field lookup.
|
||||
*/
|
||||
GetFieldNode(EnsoLanguage language, int index, Type type, String name, ModuleScope moduleScope) {
|
||||
super(language, LocalScope.root(), moduleScope, name, null);
|
||||
super(language, LocalScope.empty(), moduleScope, name, null);
|
||||
this.index = index;
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
|
@ -24,7 +24,7 @@ final class QualifiedAccessorNode extends EnsoRootNode {
|
||||
EnsoLanguage language, AtomConstructor atomConstructor, ModuleScope moduleScope) {
|
||||
super(
|
||||
language,
|
||||
LocalScope.root(),
|
||||
LocalScope.empty(),
|
||||
moduleScope,
|
||||
atomConstructor.getQualifiedName().toString(),
|
||||
null);
|
||||
|
@ -16,7 +16,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
import org.enso.compiler.context.FramePointer;
|
||||
import org.enso.compiler.pass.analyse.FramePointer;
|
||||
import org.enso.interpreter.EnsoLanguage;
|
||||
import org.enso.interpreter.node.EnsoRootNode;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
|
@ -179,7 +179,9 @@ public final class TopLevelScope implements EnsoObject {
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
var re = new RuntimeException(e);
|
||||
re.setStackTrace(e.getStackTrace());
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
package org.enso.interpreter.runtime
|
||||
|
||||
import java.util.logging.Level
|
||||
import com.oracle.truffle.api.source.{Source, SourceSection}
|
||||
import com.oracle.truffle.api.interop.InteropLibrary
|
||||
import org.enso.compiler.pass.analyse.FramePointer
|
||||
import org.enso.compiler.pass.analyse.FrameVariableNames
|
||||
import org.enso.compiler.context.{
|
||||
CompilerContext,
|
||||
FramePointer,
|
||||
LocalScope,
|
||||
NameResolutionAlgorithm
|
||||
}
|
||||
@ -264,30 +266,28 @@ class IrToTruffle(
|
||||
atomCons: AtomConstructor,
|
||||
atomDefn: Definition.Data
|
||||
): Unit = {
|
||||
def scopeInfo() = {
|
||||
atomDefn
|
||||
.unsafeGetMetadata(
|
||||
AliasAnalysis,
|
||||
"No root scope on an atom definition."
|
||||
)
|
||||
.unsafeAs[AliasMetadata.RootScope]
|
||||
}
|
||||
val scopeInfo = rootScopeInfo("atom definition", atomDefn)
|
||||
|
||||
def dataflowInfo() = atomDefn.unsafeGetMetadata(
|
||||
DataflowAnalysis,
|
||||
"No dataflow information associated with an atom."
|
||||
)
|
||||
def frameInfo() = atomDefn.unsafeGetMetadata(
|
||||
FramePointerAnalysis,
|
||||
"Method definition missing frame information."
|
||||
)
|
||||
val localScope = new LocalScope(
|
||||
None,
|
||||
() => scopeInfo().graph,
|
||||
() => scopeInfo().graph.rootScope,
|
||||
dataflowInfo
|
||||
dataflowInfo,
|
||||
frameInfo
|
||||
)
|
||||
|
||||
val argFactory =
|
||||
new DefinitionArgumentProcessor(
|
||||
scope = localScope,
|
||||
initialName = "Type " + tpDef.name
|
||||
initialName = "Type " + tpDef.name.name
|
||||
)
|
||||
val argDefs =
|
||||
new Array[ArgumentDefinition](atomDefn.arguments.size)
|
||||
@ -303,6 +303,7 @@ class IrToTruffle(
|
||||
FramePointerAnalysis,
|
||||
"No frame pointer on an argument definition."
|
||||
)
|
||||
.asInstanceOf[FramePointer]
|
||||
val slotIdx = fp.frameSlotIdx()
|
||||
argDefs(idx) = arg
|
||||
val readArg =
|
||||
@ -332,7 +333,8 @@ class IrToTruffle(
|
||||
() => scopeInfo().graph,
|
||||
() => scopeInfo().graph.rootScope,
|
||||
dataflowInfo,
|
||||
atomDefn.name.name
|
||||
atomDefn.name.name,
|
||||
frameInfo
|
||||
)
|
||||
val expressionNode =
|
||||
expressionProcessor.run(annotation.expression, true)
|
||||
@ -369,19 +371,17 @@ class IrToTruffle(
|
||||
}
|
||||
|
||||
methodDefs.foreach(methodDef => {
|
||||
def scopeInfo() = {
|
||||
methodDef
|
||||
.unsafeGetMetadata(
|
||||
AliasAnalysis,
|
||||
s"Missing scope information for method " +
|
||||
s"`${methodDef.typeName.map(_.name + ".").getOrElse("")}${methodDef.methodName.name}`."
|
||||
)
|
||||
.unsafeAs[AliasMetadata.RootScope]
|
||||
}
|
||||
lazy val where =
|
||||
s"`method ${methodDef.typeName.map(_.name + ".").getOrElse("")}${methodDef.methodName.name}`."
|
||||
val scopeInfo = rootScopeInfo(where, methodDef)
|
||||
def dataflowInfo() = methodDef.unsafeGetMetadata(
|
||||
DataflowAnalysis,
|
||||
"Method definition missing dataflow information."
|
||||
)
|
||||
def frameInfo() = methodDef.unsafeGetMetadata(
|
||||
FramePointerAnalysis,
|
||||
"Method definition missing frame information."
|
||||
)
|
||||
|
||||
@tailrec
|
||||
def getContext(tp: Expression): Option[String] = tp match {
|
||||
@ -415,7 +415,8 @@ class IrToTruffle(
|
||||
() => scopeInfo().graph,
|
||||
() => scopeInfo().graph.rootScope,
|
||||
dataflowInfo,
|
||||
fullMethodDefName
|
||||
fullMethodDefName,
|
||||
frameInfo
|
||||
)
|
||||
|
||||
scopeBuilder.registerMethod(
|
||||
@ -546,17 +547,12 @@ class IrToTruffle(
|
||||
)
|
||||
val scopeName =
|
||||
scopeElements.mkString(Constants.SCOPE_SEPARATOR)
|
||||
def scopeInfo() = {
|
||||
annotation
|
||||
.unsafeGetMetadata(
|
||||
AliasAnalysis,
|
||||
s"Missing scope information for annotation " +
|
||||
s"${annotation.name} of method " +
|
||||
scopeElements.init
|
||||
.mkString(Constants.SCOPE_SEPARATOR)
|
||||
)
|
||||
.unsafeAs[AliasMetadata.RootScope]
|
||||
}
|
||||
|
||||
lazy val where =
|
||||
s"annotation ${annotation.name} of method ${scopeElements.init
|
||||
.mkString(Constants.SCOPE_SEPARATOR)}"
|
||||
val scopeInfo = rootScopeInfo(where, annotation)
|
||||
|
||||
def dataflowInfo() = annotation.unsafeGetMetadata(
|
||||
DataflowAnalysis,
|
||||
"Missing dataflow information for annotation " +
|
||||
@ -564,12 +560,17 @@ class IrToTruffle(
|
||||
scopeElements.init
|
||||
.mkString(Constants.SCOPE_SEPARATOR)
|
||||
)
|
||||
def frameInfo() = annotation.unsafeGetMetadata(
|
||||
FramePointerAnalysis,
|
||||
"Method definition missing frame information."
|
||||
)
|
||||
val expressionProcessor = new ExpressionProcessor(
|
||||
scopeName,
|
||||
() => scopeInfo().graph,
|
||||
() => scopeInfo().graph.rootScope,
|
||||
dataflowInfo,
|
||||
methodDef.methodName.name
|
||||
methodDef.methodName.name,
|
||||
frameInfo
|
||||
)
|
||||
val expressionNode =
|
||||
expressionProcessor.run(annotation.expression, true)
|
||||
@ -599,9 +600,9 @@ class IrToTruffle(
|
||||
.annotations(annotations: _*)
|
||||
.argumentDefinitions(arguments: _*)
|
||||
if (methodDef.isPrivate) {
|
||||
funcSchemaBldr.projectPrivate();
|
||||
funcSchemaBldr.projectPrivate()
|
||||
}
|
||||
val funcSchema = funcSchemaBldr.build();
|
||||
val funcSchema = funcSchemaBldr.build()
|
||||
new RuntimeFunction(
|
||||
callTarget,
|
||||
null,
|
||||
@ -700,7 +701,7 @@ class IrToTruffle(
|
||||
.newBuilder()
|
||||
.argumentDefinitions(bodyBuilder.args(): _*)
|
||||
if (methodDef.isPrivate) {
|
||||
funcSchemaBldr.projectPrivate();
|
||||
funcSchemaBldr.projectPrivate()
|
||||
}
|
||||
val funcSchema = funcSchemaBldr.build()
|
||||
new RuntimeFunction(
|
||||
@ -767,19 +768,18 @@ class IrToTruffle(
|
||||
|
||||
// Register the conversion definitions in scope
|
||||
conversionDefs.foreach(methodDef => {
|
||||
def scopeInfo() = {
|
||||
methodDef
|
||||
.unsafeGetMetadata(
|
||||
AliasAnalysis,
|
||||
s"Missing scope information for conversion " +
|
||||
s"`${methodDef.typeName.map(_.name + ".").getOrElse("")}${methodDef.methodName.name}`."
|
||||
)
|
||||
.unsafeAs[AliasMetadata.RootScope]
|
||||
}
|
||||
lazy val where =
|
||||
s"conversion `${methodDef.typeName.map(_.name + ".").getOrElse("")}${methodDef.methodName.name}`."
|
||||
val scopeInfo = rootScopeInfo(where, methodDef)
|
||||
|
||||
def dataflowInfo() = methodDef.unsafeGetMetadata(
|
||||
DataflowAnalysis,
|
||||
"Method definition missing dataflow information."
|
||||
)
|
||||
def frameInfo() = methodDef.unsafeGetMetadata(
|
||||
FramePointerAnalysis,
|
||||
"Method definition missing frame information."
|
||||
)
|
||||
|
||||
val toOpt =
|
||||
methodDef.methodReference.typePointer match {
|
||||
@ -795,7 +795,8 @@ class IrToTruffle(
|
||||
() => scopeInfo().graph,
|
||||
() => scopeInfo().graph.rootScope,
|
||||
dataflowInfo,
|
||||
methodDef.methodName.name
|
||||
methodDef.methodName.name,
|
||||
frameInfo
|
||||
)
|
||||
|
||||
val function = methodDef.body match {
|
||||
@ -1230,10 +1231,11 @@ class IrToTruffle(
|
||||
graph: () => AliasGraph,
|
||||
scope: () => AliasScope,
|
||||
dataflowInfo: () => DataflowAnalysis.Metadata,
|
||||
initialName: String
|
||||
initialName: String,
|
||||
frameInfo: () => FramePointerAnalysis.Metadata = null
|
||||
) = {
|
||||
this(
|
||||
new LocalScope(None, graph, scope, dataflowInfo),
|
||||
new LocalScope(None, graph, scope, dataflowInfo, frameInfo),
|
||||
scopeName,
|
||||
initialName
|
||||
)
|
||||
@ -1249,9 +1251,12 @@ class IrToTruffle(
|
||||
def createChild(
|
||||
name: String,
|
||||
scope: () => AliasScope,
|
||||
initialName: String
|
||||
initialName: String,
|
||||
symbolsProvider: () => FrameVariableNames = null
|
||||
): ExpressionProcessor = {
|
||||
new ExpressionProcessor(this.scope.createChild(scope), name, initialName)
|
||||
val childScope =
|
||||
this.scope.createChild(scope, symbolsProvider = symbolsProvider)
|
||||
new ExpressionProcessor(childScope, name, initialName)
|
||||
}
|
||||
|
||||
// === Runner =============================================================
|
||||
@ -1304,7 +1309,7 @@ class IrToTruffle(
|
||||
ir.getMetadata(TypeSignatures)
|
||||
types.foreach { tpe =>
|
||||
val checkNode =
|
||||
extractAscribedType(tpe.comment.orNull, tpe.signature);
|
||||
extractAscribedType(tpe.comment.orNull, tpe.signature)
|
||||
if (checkNode != null) {
|
||||
runtimeExpression =
|
||||
ReadArgumentCheckNode.wrap(runtimeExpression, checkNode)
|
||||
@ -1334,19 +1339,19 @@ class IrToTruffle(
|
||||
*/
|
||||
private def processBlock(block: Expression.Block): RuntimeExpression = {
|
||||
if (block.suspended) {
|
||||
def scopeInfo() = {
|
||||
block
|
||||
.unsafeGetMetadata(
|
||||
AliasAnalysis,
|
||||
"Missing scope information on block."
|
||||
)
|
||||
.unsafeAs[AliasMetadata.ChildScope]
|
||||
}
|
||||
val scopeInfo = childScopeInfo("block", block)
|
||||
def frameInfo() = block
|
||||
.unsafeGetMetadata(
|
||||
FramePointerAnalysis,
|
||||
"Method definition missing frame information."
|
||||
)
|
||||
.asInstanceOf[FrameVariableNames]
|
||||
|
||||
val childFactory = this.createChild(
|
||||
"suspended-block",
|
||||
() => scopeInfo().scope,
|
||||
"suspended " + currentVarName
|
||||
"suspended " + currentVarName,
|
||||
frameInfo
|
||||
)
|
||||
val childScope = childFactory.scope
|
||||
|
||||
@ -1448,20 +1453,19 @@ class IrToTruffle(
|
||||
def processCaseBranch(
|
||||
branch: Case.Branch
|
||||
): Either[BadPatternMatch, BranchNode] = {
|
||||
def scopeInfo() = {
|
||||
branch
|
||||
.unsafeGetMetadata(
|
||||
AliasAnalysis,
|
||||
"No scope information on a case branch."
|
||||
)
|
||||
.unsafeAs[AliasMetadata.ChildScope]
|
||||
}
|
||||
|
||||
val scopeInfo = childScopeInfo("case branch", branch)
|
||||
def frameInfo() = branch
|
||||
.unsafeGetMetadata(
|
||||
FramePointerAnalysis,
|
||||
"Method definition missing frame information."
|
||||
)
|
||||
.asInstanceOf[FrameVariableNames]
|
||||
val childProcessor =
|
||||
this.createChild(
|
||||
"case_branch",
|
||||
() => scopeInfo().scope,
|
||||
"case " + currentVarName
|
||||
"case " + currentVarName,
|
||||
frameInfo
|
||||
)
|
||||
|
||||
branch.pattern match {
|
||||
@ -1607,7 +1611,7 @@ class IrToTruffle(
|
||||
BadPatternMatch.NonConstantPolyglotSymbol(symbol)
|
||||
)
|
||||
} else {
|
||||
val value = iop.readMember(polyClass, symbol);
|
||||
val value = iop.readMember(polyClass, symbol)
|
||||
val ensoValue =
|
||||
HostValueToEnsoNode.getUncached().execute(value)
|
||||
Right(ensoValue)
|
||||
@ -1834,6 +1838,7 @@ class IrToTruffle(
|
||||
FramePointerAnalysis,
|
||||
"Binding with missing frame pointer."
|
||||
)
|
||||
.asInstanceOf[FramePointer]
|
||||
|
||||
currentVarName = binding.name.name
|
||||
val slotIdx = fp.frameSlotIdx()
|
||||
@ -1853,17 +1858,19 @@ class IrToTruffle(
|
||||
function: Function,
|
||||
binding: Boolean
|
||||
): RuntimeExpression = {
|
||||
def scopeInfo() = {
|
||||
function
|
||||
.unsafeGetMetadata(AliasAnalysis, "No scope info on a function.")
|
||||
.unsafeAs[AliasMetadata.ChildScope]
|
||||
}
|
||||
val scopeInfo = childScopeInfo("function", function)
|
||||
if (function.body.isInstanceOf[Function]) {
|
||||
throw new CompilerError(
|
||||
"Lambda found directly as function body. It looks like Lambda " +
|
||||
"Consolidation hasn't run."
|
||||
)
|
||||
}
|
||||
def frameInfo() = function
|
||||
.unsafeGetMetadata(
|
||||
FramePointerAnalysis,
|
||||
"Method definition missing frame information."
|
||||
)
|
||||
.asInstanceOf[FrameVariableNames]
|
||||
|
||||
val scopeName = if (function.canBeTCO) {
|
||||
this.scopeName + "." + currentVarName
|
||||
@ -1875,7 +1882,8 @@ class IrToTruffle(
|
||||
this.createChild(
|
||||
scopeName,
|
||||
() => scopeInfo().scope,
|
||||
"case " + currentVarName
|
||||
"case " + currentVarName,
|
||||
frameInfo
|
||||
)
|
||||
|
||||
val fn = child.processFunctionBody(
|
||||
@ -1898,8 +1906,8 @@ class IrToTruffle(
|
||||
case literalName: Name.Literal =>
|
||||
val resolver = new RuntimeNameResolution()
|
||||
val fpMeta = literalName.passData.get(FramePointerAnalysis) match {
|
||||
case Some(meta: FramePointerAnalysis.FramePointerMeta) => meta
|
||||
case _ => null
|
||||
case Some(meta: FramePointer) => meta
|
||||
case _ => null
|
||||
}
|
||||
resolver.resolveName(literalName, fpMeta)
|
||||
case Name.MethodReference(
|
||||
@ -1959,17 +1967,17 @@ class IrToTruffle(
|
||||
extends NameResolutionAlgorithm[
|
||||
RuntimeExpression,
|
||||
FramePointer,
|
||||
FramePointerAnalysis.FramePointerMeta
|
||||
FramePointer
|
||||
] {
|
||||
override protected def findLocalLink(
|
||||
fpMeta: FramePointerAnalysis.FramePointerMeta
|
||||
fpMeta: FramePointer
|
||||
): Option[FramePointer] = {
|
||||
if (scope.flattenToParent && fpMeta.parentLevel() > 0) {
|
||||
Some(
|
||||
new FramePointer(fpMeta.parentLevel() - 1, fpMeta.frameSlotIdx())
|
||||
)
|
||||
} else {
|
||||
Some(fpMeta.framePointer)
|
||||
Some(fpMeta)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2059,11 +2067,11 @@ class IrToTruffle(
|
||||
|
||||
private def fileLocationFromSection(loc: IdentifiedLocation) = {
|
||||
val section =
|
||||
source.createSection(loc.location().start(), loc.location().length());
|
||||
source.createSection(loc.location().start(), loc.location().length())
|
||||
val locStr = "" + section.getStartLine() + ":" + section
|
||||
.getStartColumn() + "-" + section.getEndLine() + ":" + section
|
||||
.getEndColumn()
|
||||
source.getName() + "[" + locStr + "]";
|
||||
source.getName() + "[" + locStr + "]"
|
||||
}
|
||||
|
||||
/** Generates a runtime implementation for compile error nodes.
|
||||
@ -2213,6 +2221,7 @@ class IrToTruffle(
|
||||
FramePointerAnalysis,
|
||||
"No frame pointer on an argument definition."
|
||||
)
|
||||
.asInstanceOf[FramePointer]
|
||||
val slotIdx = fp.frameSlotIdx()
|
||||
val readArg =
|
||||
ReadArgumentNode.build(
|
||||
@ -2432,14 +2441,7 @@ class IrToTruffle(
|
||||
): callable.argument.CallArgument =
|
||||
arg match {
|
||||
case CallArgument.Specified(name, value, _, _) =>
|
||||
def scopeInfo() = {
|
||||
arg
|
||||
.unsafeGetMetadata(
|
||||
AliasAnalysis,
|
||||
"No scope attached to a call argument."
|
||||
)
|
||||
.unsafeAs[AliasMetadata.ChildScope]
|
||||
}
|
||||
val scopeInfo = childScopeInfo("call argument", arg)
|
||||
|
||||
def valueHasSomeTypeCheck() =
|
||||
value.getMetadata(TypeSignatures).isDefined
|
||||
@ -2452,7 +2454,17 @@ class IrToTruffle(
|
||||
}
|
||||
|
||||
val childScope = if (shouldCreateClosureRootNode) {
|
||||
scope.createChild(() => scopeInfo().scope)
|
||||
def frameInfo() = arg
|
||||
.unsafeGetMetadata(
|
||||
FramePointerAnalysis,
|
||||
"Method definition missing frame information."
|
||||
)
|
||||
.asInstanceOf[FrameVariableNames]
|
||||
|
||||
scope.createChild(
|
||||
() => scopeInfo().scope,
|
||||
symbolsProvider = frameInfo
|
||||
)
|
||||
} else {
|
||||
// Note [Scope Flattening]
|
||||
scope.createChild(() => scopeInfo().scope, flattenToParent = true)
|
||||
@ -2618,4 +2630,43 @@ class IrToTruffle(
|
||||
|
||||
private def scopeAssociatedType =
|
||||
scopeBuilder.asModuleScope().getAssociatedType
|
||||
|
||||
private def rootScopeInfo(
|
||||
where: => String,
|
||||
ir: IR
|
||||
): () => AliasMetadata.RootScope = {
|
||||
def readScopeInfo() = {
|
||||
val raw =
|
||||
ir.unsafeGetMetadata(AliasAnalysis, s"No root scope for ${where}.")
|
||||
val scope = raw.unsafeAs[AliasMetadata.RootScope]
|
||||
|
||||
val log = context.getLogger()
|
||||
if (log.isLoggable(Level.FINEST)) {
|
||||
val allDefs = scope.graph.rootScope.allDefinitions
|
||||
log.log(Level.FINEST, s"Scope for ${where} loaded with {0}", allDefs)
|
||||
}
|
||||
scope
|
||||
}
|
||||
readScopeInfo
|
||||
}
|
||||
|
||||
private def childScopeInfo(
|
||||
where: => String,
|
||||
ir: IR
|
||||
): () => AliasMetadata.ChildScope = {
|
||||
def readScopeInfo() = {
|
||||
val raw =
|
||||
ir.unsafeGetMetadata(AliasAnalysis, s"No root scope for ${where}.")
|
||||
val scope = raw.unsafeAs[AliasMetadata.ChildScope]
|
||||
|
||||
val log = context.getLogger()
|
||||
if (log.isLoggable(Level.FINEST)) {
|
||||
val allDefs = scope.graph.rootScope.allDefinitions
|
||||
log.log(Level.FINEST, s"Scope for ${where} loaded with {0}", allDefs)
|
||||
}
|
||||
scope
|
||||
}
|
||||
readScopeInfo
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user