diff --git a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/IRHelpers.java b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/IRHelpers.java new file mode 100644 index 000000000000..a536eab89813 --- /dev/null +++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/IRHelpers.java @@ -0,0 +1,79 @@ +package org.enso.compiler.pass; + +import java.util.ArrayDeque; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Set; +import org.enso.compiler.core.IR; +import org.enso.scala.wrapper.ScalaConversions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class IRHelpers { + private static final Logger LOG = LoggerFactory.getLogger(IRHelpers.class); + private static HashSet reportedIdentityHashCodes; + + private IRHelpers() {} + + /** + * Processes whole IR subtree to find (top most) elements that are referenced multiple times. + * + * @param root the root of IR tree to process + * @return set of IR elements that appear at least twice + */ + private static Set findTopMostDuplicates(IR root) { + var foundIR = new IdentityHashMap(); + var irToProcess = new ArrayDeque(); + irToProcess.add(root); + while (!irToProcess.isEmpty()) { + var ir = irToProcess.remove(); + if (foundIR.containsKey(ir)) { + foundIR.put(ir, 1); + } else { + foundIR.put(ir, 0); + irToProcess.addAll(ScalaConversions.asJava(ir.children())); + } + } + var it = foundIR.entrySet().iterator(); + while (it.hasNext()) { + if (it.next().getValue() == 0) { + it.remove(); + } + } + return foundIR.keySet(); + } + + static IRType checkDuplicates(String msg, IRType ir) { + var duplicates = findTopMostDuplicates(ir); + if (duplicates.isEmpty()) { + return ir; + } else { + if (reportedIdentityHashCodes == null) { + reportedIdentityHashCodes = new HashSet<>(); + } + var all = ir.preorder(); + for (var dupl : duplicates) { + if (!reportedIdentityHashCodes.add(System.identityHashCode(dupl))) { + continue; + } + LOG.error("Duplicate found after " + msg + ": " + toString(dupl)); + all.foreach( + e -> { + if (e.children().contains(dupl)) { + LOG.error(" referenced by " + toString(e)); + } + return null; + }); + } + } + return ir; + } + + private static String toString(IR ir) { + return ir.getClass().getName() + + "@" + + Integer.toHexString(System.identityHashCode(ir)) + + ":" + + ir.showCode(); + } +} 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 9c643deeb200..08bc38d690df 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 @@ -173,7 +173,12 @@ class PassManager( pendingMiniPasses.clear() if (combinedPass != null) { logger.trace(" flushing pending mini pass: {}", combinedPass) - miniPassCompile(combinedPass, in) + val res = miniPassCompile(combinedPass, in) + IRHelpers.checkDuplicates( + "Flushing mini passes: " + combinedPass, + res + ) + res } else { in } @@ -220,7 +225,8 @@ class PassManager( " mega running: {}", megaPass ) - megaPassCompile(megaPass, flushedIR, context) + val res = megaPassCompile(megaPass, flushedIR, context) + IRHelpers.checkDuplicates("" + megaPass.getClass().getName(), res) } } diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/desugar/Imports.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/desugar/Imports.scala index 51cfcc0588b2..1188afe76c96 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/desugar/Imports.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/desugar/Imports.scala @@ -50,7 +50,8 @@ case object Imports extends IRPass { val parts = newName.parts if (parts.length == 2) { i.copy( - name = newName.copy(parts = parts :+ mainModuleName), + name = + newName.copy(parts = parts :+ mainModuleName.duplicate()), rename = computeRename( i.rename, i.onlyNames.nonEmpty || i.isAll, diff --git a/lib/scala/logging-truffle-connector/src/main/scala/org/enso/truffleloggerwrapper/TruffleLoggerWrapper.scala b/lib/scala/logging-truffle-connector/src/main/scala/org/enso/truffleloggerwrapper/TruffleLoggerWrapper.scala index 603eee0b7302..fda39dcd8506 100644 --- a/lib/scala/logging-truffle-connector/src/main/scala/org/enso/truffleloggerwrapper/TruffleLoggerWrapper.scala +++ b/lib/scala/logging-truffle-connector/src/main/scala/org/enso/truffleloggerwrapper/TruffleLoggerWrapper.scala @@ -22,8 +22,11 @@ class TruffleLoggerWrapper(name: String, masking: Masking) extends Logger { override def getName: String = underlying.getName - private def isEnabled(level: Level): Boolean = + private def isEnabled(level: Level): Boolean = try { underlying.isLoggable(level) + } catch { + case _: IllegalStateException => false + } private def log( level: Level,