From 2f598f5cfb0a05b8be224fd57feb5961ff440bba Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Mon, 3 Feb 2025 15:11:37 +0100 Subject: [PATCH 1/2] Fill in line numbers for IR.bgv files --- .../enso/compiler/dump/igv/ASTLocation.java | 44 +++++++----------- .../org/enso/compiler/dump/igv/ASTNode.java | 6 +-- .../enso/compiler/dump/igv/EnsoModuleAST.java | 45 +++++++------------ .../org/enso/compiler/dump/igv/IGVDumper.java | 30 ++++++------- .../dump/service/IRDumpSingleton.java | 3 +- .../enso/compiler/dump/service/IRDumper.java | 19 ++------ .../enso/compiler/dump/service/IRSource.java | 14 ++++++ .../compiler/context/CompilerContext.java | 6 +++ .../org/enso/compiler/pass/PassManager.scala | 45 ++++++++----------- .../runtime/TruffleCompilerContext.java | 16 +++++++ .../enso/test/utils/IRDumperTestWrapper.java | 7 ++- 11 files changed, 112 insertions(+), 123 deletions(-) create mode 100644 engine/runtime-compiler-dump/src/main/java/org/enso/compiler/dump/service/IRSource.java diff --git a/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/ASTLocation.java b/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/ASTLocation.java index 7b5493945eda..a40b188a3c67 100644 --- a/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/ASTLocation.java +++ b/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/ASTLocation.java @@ -1,51 +1,37 @@ package org.enso.compiler.dump.igv; -import java.io.File; import java.net.URI; +import org.enso.compiler.core.IR; import org.enso.compiler.core.ir.IdentifiedLocation; +import org.enso.compiler.dump.service.IRSource; final class ASTLocation { - private final int lineNum; - // May be null - private final URI locationUri; - private final int offsetStart; - private final int offsetEnd; - - private ASTLocation(int lineNum, URI locationUri, int offsetStart, int offsetEnd) { - this.lineNum = lineNum; - this.locationUri = locationUri; - this.offsetStart = offsetStart; - this.offsetEnd = offsetEnd; + private final IRSource ctx; + private final IdentifiedLocation loc; + + private ASTLocation(IRSource ctx, IdentifiedLocation loc) { + this.ctx = ctx; + this.loc = loc; } - public static ASTLocation fromIdentifiedLocation(IdentifiedLocation loc, File srcFile) { - int offStart = -1; - int offEnd = -1; - int lineNum = 1; - URI uri = null; - if (loc != null) { - offStart = loc.start(); - offEnd = loc.end(); - } - if (srcFile != null) { - uri = srcFile.toURI(); - } - return new ASTLocation(lineNum, uri, offStart, offEnd); + public static ASTLocation fromIdentifiedLocation( + IdentifiedLocation loc, IRSource ctx) { + return new ASTLocation(ctx, loc); } public int getLineNum() { - return lineNum; + return loc == null ? -1 : ctx.lineMap().apply(loc); } public int getOffsetStart() { - return offsetStart; + return loc == null ? -1 : loc.start(); } public int getOffsetEnd() { - return offsetEnd; + return loc == null ? -1 : loc.end(); } public URI getLocationUri() { - return locationUri; + return ctx.loc(); } } diff --git a/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/ASTNode.java b/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/ASTNode.java index c1d9f34a6618..32e07cbc28cc 100644 --- a/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/ASTNode.java +++ b/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/ASTNode.java @@ -1,6 +1,5 @@ package org.enso.compiler.dump.igv; -import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; @@ -9,6 +8,7 @@ import java.util.stream.Collectors; import org.enso.compiler.core.IR; import org.enso.compiler.core.ir.MetadataStorage; +import org.enso.compiler.dump.service.IRSource; final class ASTNode { @@ -72,10 +72,10 @@ static final class Builder { private final Map properties = new LinkedHashMap<>(); private ASTLocation location; - public static Builder fromIr(IR ir, File srcFile) { + public static Builder fromIr(IR ir, IRSource ctx) { var bldr = new Builder(); var label = Utils.label(ir); - var location = ASTLocation.fromIdentifiedLocation(ir.identifiedLocation(), srcFile); + var location = ASTLocation.fromIdentifiedLocation(ir.identifiedLocation(), ctx); bldr.object = ir; bldr.location = location; bldr.property("label", label); diff --git a/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/EnsoModuleAST.java b/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/EnsoModuleAST.java index 96bd5ee65422..0e5d9a7c4585 100644 --- a/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/EnsoModuleAST.java +++ b/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/EnsoModuleAST.java @@ -1,6 +1,6 @@ package org.enso.compiler.dump.igv; -import java.io.File; +import java.net.URI; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.HashMap; @@ -28,6 +28,7 @@ import org.enso.compiler.core.ir.module.scope.Import; import org.enso.compiler.core.ir.module.scope.definition.Method; import org.enso.compiler.core.ir.module.scope.imports.Polyglot; +import org.enso.compiler.dump.service.IRSource; /** * Implemented only for dumping the AST to IGV. Heavily inspired by the internal {@code @@ -39,9 +40,7 @@ final class EnsoModuleAST { private final ASTNode root; /** Underlying source file. May be null. */ - private final File srcFile; - - private final String moduleName; + private final IRSource ctx; private final Map nodes = new HashMap<>(); @@ -53,19 +52,14 @@ final class EnsoModuleAST { private final Map nodeIds; - private EnsoModuleAST( - Module moduleIr, File srcFile, String moduleName, Map nodeIds) { - this.nodeIds = nodeIds; - this.srcFile = srcFile; - this.moduleName = moduleName; - this.root = buildTree(moduleIr); - } - - private EnsoModuleAST(Expression expr, String moduleName, Map nodeIds) { + private EnsoModuleAST(IRSource ctx, Map nodeIds) { this.nodeIds = nodeIds; - this.srcFile = null; - this.moduleName = moduleName; - this.root = buildTree(expr); + this.ctx = ctx; + this.root = switch (ctx.ir()) { + case Module m -> buildTree(m); + case Expression e -> buildTree(e); + case null, default -> throw new IllegalArgumentException("ir: " + ctx.ir()); + }; } /** @@ -73,22 +67,17 @@ private EnsoModuleAST(Expression expr, String moduleName, Map nod * @param moduleName FQN of the module. * @param nodeIds Mapping of IR node UUIDs to sequential IDs expected by the IGV. */ - static EnsoModuleAST fromModuleIR( - Module module, File srcFile, String moduleName, Map nodeIds) { - return new EnsoModuleAST(module, srcFile, moduleName, nodeIds); - } - - static EnsoModuleAST fromExpressionIR( - Expression expr, String moduleName, Map nodeIds) { - return new EnsoModuleAST(expr, moduleName, nodeIds); + static EnsoModuleAST create( + IRSource ctx, Map nodeIds) { + return new EnsoModuleAST(ctx, nodeIds); } - public File getSrcFile() { - return srcFile; + public URI getSrcFile() { + return ctx.loc(); } public String getModuleName() { - return moduleName; + return ctx.name(); } public List getNodes() { @@ -463,7 +452,7 @@ private ASTNode buildTree(DefinitionArgument argument) { } private ASTNode newNode(IR ir, Map props) { - ASTNode.Builder bldr = ASTNode.Builder.fromIr(ir, srcFile); + ASTNode.Builder bldr = ASTNode.Builder.fromIr(ir, ctx); var nodeId = nodeIds.get(ir.getId()); if (nodeId == null) { var lastSeqId = nodeIds.size(); diff --git a/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/IGVDumper.java b/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/IGVDumper.java index 25c3fcdf9c20..1cb1cb906cf8 100644 --- a/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/IGVDumper.java +++ b/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/IGVDumper.java @@ -1,6 +1,5 @@ package org.enso.compiler.dump.igv; -import java.io.File; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.SocketChannel; @@ -16,6 +15,7 @@ import org.enso.compiler.core.ir.Expression; import org.enso.compiler.core.ir.Module; import org.enso.compiler.dump.service.IRDumper; +import org.enso.compiler.dump.service.IRSource; import org.graalvm.graphio.GraphOutput; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,7 +50,7 @@ private GraphOutput graphOutput() { .blocks(EnsoModuleAST.AST_DUMP_STRUCTURE) .elementsAndLocations( EnsoModuleAST.AST_DUMP_STRUCTURE, EnsoModuleAST.AST_DUMP_STRUCTURE) - .attr("type", "Enso IR") + .attr("ensoIrVersion", "1.0") .build(channel); } catch (IOException e) { throw new IllegalStateException( @@ -74,26 +74,22 @@ private static WritableByteChannel createChannel(String moduleName) { } @Override - public void dumpModule(Module ir, String graphName, File srcFile, String afterPass) { - assert graphName.equals(this.moduleName); - dumpTask(ir, graphName, srcFile, afterPass); + public void dumpModule(IRSource ctx) { + assert ctx.name().equals(this.moduleName); + dumpTask(ctx); } @Override - public void dumpExpression(Expression expr, String graphName, String afterPass) { - dumpTask(expr, graphName, null, afterPass); + public void dumpExpression(IRSource ctx) { + dumpTask(ctx); } - private void dumpTask(IR ir, String moduleName, File srcFile, String afterPass) { + @SuppressWarnings("unchecked") + private void dumpTask(IRSource ctx) { + var ir = ctx.ir(); + var afterPass = ctx.afterPass(); LOGGER.trace("[{}] Creating EnsoModuleAST after pass {}", moduleName, afterPass); - EnsoModuleAST moduleAst; - if (ir instanceof Module moduleIr) { - moduleAst = EnsoModuleAST.fromModuleIR(moduleIr, srcFile, moduleName, nodeIds); - } else if (ir instanceof Expression expr) { - moduleAst = EnsoModuleAST.fromExpressionIR(expr, moduleName, nodeIds); - } else { - throw new IllegalArgumentException("Unsupported IR type: " + ir.getClass()); - } + var moduleAst = EnsoModuleAST.create(ctx, nodeIds); try { if (!groupCreated) { var groupProps = groupProps(moduleName, moduleAst); @@ -115,7 +111,7 @@ private static Map groupProps(String moduleName, EnsoModuleAST g var props = new HashMap(); props.put("moduleName", moduleName); props.put("date", LocalDateTime.now()); - props.put("srcFile", graph.getSrcFile() == null ? null : graph.getSrcFile().getAbsolutePath()); + props.put("srcFile", graph.getSrcFile() == null ? null : graph.getSrcFile().toString()); return props; } diff --git a/engine/runtime-compiler-dump/src/main/java/org/enso/compiler/dump/service/IRDumpSingleton.java b/engine/runtime-compiler-dump/src/main/java/org/enso/compiler/dump/service/IRDumpSingleton.java index 62e0b842621f..0cbc6e7e7eaa 100644 --- a/engine/runtime-compiler-dump/src/main/java/org/enso/compiler/dump/service/IRDumpSingleton.java +++ b/engine/runtime-compiler-dump/src/main/java/org/enso/compiler/dump/service/IRDumpSingleton.java @@ -1,6 +1,5 @@ package org.enso.compiler.dump.service; -import java.io.File; import java.util.ServiceLoader; import org.enso.compiler.core.ir.Module; @@ -29,7 +28,7 @@ public IRDumper create(String moduleName) { public void shutdown() {} @Override - public void dumpModule(Module ir, String graphName, File srcFile, String afterPass) {} + public void dumpModule(IRSource ir) {} @Override public void close() {} diff --git a/engine/runtime-compiler-dump/src/main/java/org/enso/compiler/dump/service/IRDumper.java b/engine/runtime-compiler-dump/src/main/java/org/enso/compiler/dump/service/IRDumper.java index 567803f79b7c..2e6dad15fdf9 100644 --- a/engine/runtime-compiler-dump/src/main/java/org/enso/compiler/dump/service/IRDumper.java +++ b/engine/runtime-compiler-dump/src/main/java/org/enso/compiler/dump/service/IRDumper.java @@ -1,6 +1,5 @@ package org.enso.compiler.dump.service; -import java.io.File; import org.enso.compiler.core.ir.Expression; import org.enso.compiler.core.ir.Module; @@ -9,22 +8,12 @@ public interface IRDumper { /** * Dumps module IR. * - * @param ir IR of the module to dump - * @param graphName Name of the graph to be dumped. Usually a fully-qualified module name. - * @param srcFile Source file of the module. May be null. - * @param afterPass Name of the pass that this dumper runs after. Corresponds to name of the - * subgraph. + * @param dump what to dump */ - void dumpModule(Module ir, String graphName, File srcFile, String afterPass); + void dumpModule(IRSource dump); - /** - * Dumps a single expression IR. - * - * @param expr the IR. - * @param graphName Name of the graph to be dumped. May contain spaces. - * @param afterPass Name of the subgraph. - */ - default void dumpExpression(Expression expr, String graphName, String afterPass) { + /** Dumps a single expression IR. */ + default void dumpExpression(IRSource dump) { // nop } diff --git a/engine/runtime-compiler-dump/src/main/java/org/enso/compiler/dump/service/IRSource.java b/engine/runtime-compiler-dump/src/main/java/org/enso/compiler/dump/service/IRSource.java new file mode 100644 index 000000000000..680dc181430d --- /dev/null +++ b/engine/runtime-compiler-dump/src/main/java/org/enso/compiler/dump/service/IRSource.java @@ -0,0 +1,14 @@ +package org.enso.compiler.dump.service; + +import java.net.URI; +import java.util.function.Function; +import org.enso.compiler.core.IR; +import org.enso.compiler.core.ir.IdentifiedLocation; + +/** Information about an IR dumping. */ +public record IRSource( + AnIR ir, + String name, + String afterPass, + URI loc, + Function lineMap) {} diff --git a/engine/runtime-compiler/src/main/java/org/enso/compiler/context/CompilerContext.java b/engine/runtime-compiler/src/main/java/org/enso/compiler/context/CompilerContext.java index aaf96abdbdc7..dc175e0891a0 100644 --- a/engine/runtime-compiler/src/main/java/org/enso/compiler/context/CompilerContext.java +++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/context/CompilerContext.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.io.PrintStream; +import java.net.URI; import java.util.List; import java.util.concurrent.Future; import java.util.function.Consumer; @@ -12,6 +13,7 @@ import org.enso.compiler.Passes; import org.enso.compiler.core.CompilerStub; import org.enso.compiler.core.ir.Diagnostic; +import org.enso.compiler.core.ir.IdentifiedLocation; import org.enso.compiler.data.BindingsMap; import org.enso.compiler.data.CompilerConfig; import org.enso.compiler.data.IdMap; @@ -138,8 +140,12 @@ public abstract static class Module { public abstract CharSequence getCharacters() throws IOException; + public abstract int findLine(IdentifiedLocation loc); + public abstract String getPath(); + public abstract URI getUri(); + public abstract Package getPackage(); public abstract QualifiedName getName(); diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/PassManager.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/PassManager.scala index bf0f57221b03..d246cb3a3e8d 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/PassManager.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/PassManager.scala @@ -1,12 +1,12 @@ package org.enso.compiler.pass import org.slf4j.LoggerFactory -import org.enso.compiler.context.{InlineContext, ModuleContext} +import org.enso.compiler.context.{CompilerContext, InlineContext, ModuleContext} import org.enso.compiler.core.ir.{Expression, Module} import org.enso.compiler.core.{CompilerError, IR} import org.enso.compiler.dump.service.IRDumper +import org.enso.compiler.dump.service.IRSource -import java.io.File import scala.collection.mutable.ListBuffer // TODO [AA] In the future, the pass ordering should be _computed_ from the list @@ -87,22 +87,13 @@ class PassManager( val newContext = moduleContext.copy(passConfiguration = Some(passConfiguration)) - def getSrcFile(): File = { - val modPath = newContext.module.getPath - if (modPath == null) { - null - } else { - new File(modPath) - } - } - runPasses[Module, ModuleContext]( ir, newContext, passGroup, moduleName = Some(moduleContext.getName().toString), irDumper = irDumper, - getSrcFile = getSrcFile, + module = newContext.module, createMiniPass = (factory, ctx) => factory.createForModuleCompilation(ctx), miniPassCompile = (miniPass, ir) => @@ -145,21 +136,12 @@ class PassManager( val newContext = inlineContext.copy(passConfiguration = Some(passConfiguration)) - def getSrcFile(): File = { - val modPath = inlineContext.getModule().getPath - if (modPath == null) { - null - } else { - new File(modPath) - } - } - runPasses[Expression, InlineContext]( ir, newContext, passGroup, moduleName = null, - getSrcFile = getSrcFile, + module = inlineContext.getModule(), irDumper = None, createMiniPass = (factory, ctx) => factory.createForInlineCompilation(ctx), @@ -174,11 +156,20 @@ class PassManager( moduleName: Option[String], irDumper: Option[IRDumper], passName: String, - getSrcFile: () => File + module: CompilerContext.Module ): Unit = { (ir, moduleName, irDumper) match { case (moduleIr: Module, Some(modName), Some(dumper)) => - dumper.dumpModule(moduleIr, modName, getSrcFile(), passName) + val irSrc = new IRSource( + moduleIr, + modName, + passName, + module.getUri(), + loc => { + module.findLine(loc) + } + ); + dumper.dumpModule(irSrc) case _ => () } } @@ -198,7 +189,7 @@ class PassManager( passGroup: PassGroup, moduleName: Option[String], irDumper: Option[IRDumper], - getSrcFile: () => File, + module: CompilerContext.Module, createMiniPass: (MiniPassFactory, ContextType) => MiniIRPass, miniPassCompile: (MiniIRPass, IRType) => IRType, megaPassCompile: (IRPass, IRType, ContextType) => IRType @@ -214,7 +205,7 @@ class PassManager( if (combinedPass != null) { logger.trace(" flushing pending mini pass: {}", combinedPass) val ret = miniPassCompile(combinedPass, in) - dump(ret, moduleName, irDumper, combinedPass.toString, getSrcFile) + dump(ret, moduleName, irDumper, combinedPass.toString, module) ret } else { in @@ -263,7 +254,7 @@ class PassManager( megaPass ) val ret = megaPassCompile(megaPass, flushedIR, context) - dump(ret, moduleName, irDumper, megaPass.toString, getSrcFile) + dump(ret, moduleName, irDumper, megaPass.toString, module) ret } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/TruffleCompilerContext.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/TruffleCompilerContext.java index df796ca8849e..0150f03374ba 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/TruffleCompilerContext.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/TruffleCompilerContext.java @@ -8,6 +8,7 @@ import com.oracle.truffle.api.source.Source; import java.io.IOException; import java.io.PrintStream; +import java.net.URI; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -891,6 +892,21 @@ public String toString() { sb.append('}'); return sb.toString(); } + + @Override + public int findLine(IdentifiedLocation loc) { + var ss = module.createSection(loc.start(), loc.length()); + return ss.getStartLine(); + } + + @Override + public URI getUri() { + try { + return module.getSource().getURI(); + } catch (IOException ex) { + return null; + } + } } private static void emitIOException() throws IOException {} diff --git a/lib/java/test-utils/src/main/java/org/enso/test/utils/IRDumperTestWrapper.java b/lib/java/test-utils/src/main/java/org/enso/test/utils/IRDumperTestWrapper.java index 3cc74d67b550..0b054021cbbd 100644 --- a/lib/java/test-utils/src/main/java/org/enso/test/utils/IRDumperTestWrapper.java +++ b/lib/java/test-utils/src/main/java/org/enso/test/utils/IRDumperTestWrapper.java @@ -6,6 +6,7 @@ import org.enso.compiler.core.ir.Expression; import org.enso.compiler.core.ir.Module; import org.enso.compiler.dump.service.IRDumpFactoryService; +import org.enso.compiler.dump.service.IRSource; /** Utility class for {@link org.enso.compiler.dump.service.IRDumper}. */ public final class IRDumperTestWrapper implements AutoCloseable { @@ -24,9 +25,11 @@ public void dump(IR ir, String moduleName, String passName) { dumpers.put(moduleName, dumper); } if (ir instanceof Module modIr) { - dumper.dumpModule(modIr, moduleName, null, passName); + var src = new IRSource(modIr, moduleName, passName, null, null); + dumper.dumpModule(src); } else if (ir instanceof Expression expr) { - dumper.dumpExpression(expr, moduleName, passName); + var src = new IRSource(expr, moduleName, passName, null, null); + dumper.dumpExpression(src); } else { throw new IllegalArgumentException("Unsupported IR type: " + ir.getClass()); } From bad28ddd535847bd8302ac339cc6a1ba8c6c77f2 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 6 Feb 2025 07:40:16 +0100 Subject: [PATCH 2/2] Updating information about the ctx field --- .../main/java/org/enso/compiler/dump/igv/EnsoModuleAST.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/EnsoModuleAST.java b/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/EnsoModuleAST.java index 0e5d9a7c4585..cff25076a1f5 100644 --- a/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/EnsoModuleAST.java +++ b/engine/runtime-compiler-dump-igv/src/main/java/org/enso/compiler/dump/igv/EnsoModuleAST.java @@ -39,7 +39,7 @@ final class EnsoModuleAST { private final ASTNode root; - /** Underlying source file. May be null. */ + /** Information about underlying source. */ private final IRSource ctx; private final Map nodes = new HashMap<>(); @@ -54,6 +54,7 @@ final class EnsoModuleAST { private EnsoModuleAST(IRSource ctx, Map nodeIds) { this.nodeIds = nodeIds; + assert ctx != null; this.ctx = ctx; this.root = switch (ctx.ir()) { case Module m -> buildTree(m);