diff --git a/core/src/main/java/org/teavm/model/util/PhiUpdater.java b/core/src/main/java/org/teavm/model/util/PhiUpdater.java index 7a30f1a41..d12af3c54 100644 --- a/core/src/main/java/org/teavm/model/util/PhiUpdater.java +++ b/core/src/main/java/org/teavm/model/util/PhiUpdater.java @@ -23,6 +23,7 @@ import java.util.Map; import org.teavm.common.DominatorTree; import org.teavm.common.Graph; import org.teavm.common.GraphUtils; +import org.teavm.common.IntegerArray; import org.teavm.model.BasicBlock; import org.teavm.model.Incoming; import org.teavm.model.Instruction; @@ -82,6 +83,11 @@ public class PhiUpdater { private List> synthesizedPhis = new ArrayList<>(); private List> synthesizedJoints = new ArrayList<>(); private boolean[] usedDefinitions; + private IntegerArray variableToSourceMap = new IntegerArray(10); + + public int getSourceVariable(int var) { + return variableToSourceMap.get(var); + } public void updatePhis(Program program, Variable[] arguments) { if (program.basicBlockCount() == 0) { @@ -93,8 +99,11 @@ public class PhiUpdater { domFrontiers = new int[cfg.size()][]; variableMap = new Variable[program.variableCount()]; usedDefinitions = new boolean[program.variableCount()]; + for (int i = 0; i < program.variableCount(); ++i) { + variableToSourceMap.add(-1); + } for (int i = 0; i < arguments.length; ++i) { - variableMap[i] = arguments[i]; + mapVariable(i, arguments[i]); usedDefinitions[i] = true; } phiMap = new Phi[program.basicBlockCount()][]; @@ -175,13 +184,13 @@ public class PhiUpdater { for (Phi phi : synthesizedPhis.get(index)) { Variable var = program.createVariable(); var.getDebugNames().addAll(phi.getReceiver().getDebugNames()); - variableMap[phi.getReceiver().getIndex()] = var; + mapVariable(phi.getReceiver().getIndex(), var); phi.setReceiver(var); } for (TryCatchJoint joint : synthesizedJoints.get(index)) { Variable var = program.createVariable(); var.getDebugNames().addAll(joint.getReceiver().getDebugNames()); - variableMap[joint.getReceiver().getIndex()] = var; + mapVariable(joint.getReceiver().getIndex(), var); joint.setReceiver(var); } for (Phi phi : currentBlock.getPhis()) { @@ -320,10 +329,18 @@ public class PhiUpdater { private Variable define(Variable var) { Variable original = var; var = introduce(var, false); - variableMap[original.getIndex()] = var; + mapVariable(original.getIndex(), var); return var; } + private void mapVariable(int index, Variable var) { + variableMap[index] = var; + while (variableToSourceMap.size() <= var.getIndex()) { + variableToSourceMap.add(-1); + } + variableToSourceMap.set(var.getIndex(), index); + } + private Variable introduce(Variable var, boolean clear) { Variable original = var; Variable old = variableMap[var.getIndex()]; diff --git a/core/src/main/java/org/teavm/parsing/Parser.java b/core/src/main/java/org/teavm/parsing/Parser.java index dce194b41..0da023abe 100644 --- a/core/src/main/java/org/teavm/parsing/Parser.java +++ b/core/src/main/java/org/teavm/parsing/Parser.java @@ -15,22 +15,26 @@ */ package org.teavm.parsing; +import com.carrotsearch.hppc.IntIntMap; +import com.carrotsearch.hppc.IntIntOpenHashMap; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.JSRInlinerAdapter; import org.objectweb.asm.tree.*; +import org.teavm.common.Graph; +import org.teavm.common.GraphUtils; import org.teavm.model.*; +import org.teavm.model.util.DefinitionExtractor; import org.teavm.model.util.PhiUpdater; +import org.teavm.model.util.ProgramUtils; import org.teavm.optimization.UnreachableBasicBlockEliminator; -/** - * - * @author Alexey Andreev - */ public final class Parser { private Parser() { } @@ -45,13 +49,17 @@ public final class Parser { ValueType[] signature = MethodDescriptor.parseSignature(node.desc); MethodHolder method = new MethodHolder(node.name, signature); parseModifiers(node.access, method); + ProgramParser programParser = new ProgramParser(); programParser.setFileName(fileName); Program program = programParser.parse(node, className); new UnreachableBasicBlockEliminator().optimize(program); PhiUpdater phiUpdater = new PhiUpdater(); - phiUpdater.updatePhis(program, applySignature(program, method.getParameterTypes())); + Variable[] argumentMapping = applySignature(program, method.getParameterTypes()); + phiUpdater.updatePhis(program, argumentMapping); method.setProgram(program); + applyDebugNames(program, phiUpdater, programParser, argumentMapping); + parseAnnotations(method.getAnnotations(), node.visibleAnnotations, node.invisibleAnnotations); while (program.variableCount() <= method.parameterCount()) { program.createVariable(); @@ -67,6 +75,110 @@ public final class Parser { return method; } + private static void applyDebugNames(Program program, PhiUpdater phiUpdater, ProgramParser parser, + Variable[] argumentMapping) { + if (program.basicBlockCount() == 0) { + return; + } + + IntIntMap[] blockEntryVariableMappings = getBlockEntryVariableMappings(program, phiUpdater, argumentMapping); + + DefinitionExtractor defExtractor = new DefinitionExtractor(); + Map debugNames = new HashMap<>(); + for (int i = 0; i < program.basicBlockCount(); ++i) { + BasicBlock block = program.basicBlockAt(i); + IntIntMap varMap = blockEntryVariableMappings[i]; + for (Instruction insn : block.getInstructions()) { + insn.acceptVisitor(defExtractor); + Map newDebugNames = parser.getDebugNames(insn); + if (newDebugNames != null) { + debugNames = newDebugNames; + } + for (Variable definedVar : defExtractor.getDefinedVariables()) { + int sourceVar = phiUpdater.getSourceVariable(definedVar.getIndex()); + if (sourceVar >= 0) { + varMap.put(sourceVar, definedVar.getIndex()); + } + } + for (Map.Entry debugName : debugNames.entrySet()) { + int receiver = varMap.getOrDefault(debugName.getKey(), -1); + if (receiver >= 0) { + program.variableAt(receiver).getDebugNames().add(debugName.getValue()); + } + } + } + } + } + + private static IntIntMap[] getBlockEntryVariableMappings(Program program, PhiUpdater phiUpdater, + Variable[] argumentMapping) { + class Step { + int node; + IntIntMap varMap; + + Step(int node, IntIntMap varMap) { + this.node = node; + this.varMap = varMap; + } + } + + IntIntMap[] result = new IntIntMap[program.basicBlockCount()]; + DefinitionExtractor defExtractor = new DefinitionExtractor(); + Graph cfg = ProgramUtils.buildControlFlowGraph(program); + Graph dom = GraphUtils.buildDominatorGraph(GraphUtils.buildDominatorTree(cfg), cfg.size()); + Step[] stack = new Step[program.basicBlockCount()]; + int top = 0; + + IntIntOpenHashMap entryVarMap = new IntIntOpenHashMap(); + for (int i = 0; i < argumentMapping.length; ++i) { + Variable arg = argumentMapping[i]; + if (arg != null) { + entryVarMap.put(i, arg.getIndex()); + } + } + stack[top++] = new Step(0, entryVarMap); + + while (top > 0) { + Step step = stack[--top]; + int node = step.node; + IntIntMap varMap = new IntIntOpenHashMap(step.varMap); + BasicBlock block = program.basicBlockAt(node); + + for (TryCatchJoint joint : block.getTryCatchJoints()) { + int receiver = joint.getReceiver().getIndex(); + int sourceVar = phiUpdater.getSourceVariable(receiver); + if (sourceVar >= 0) { + varMap.put(sourceVar, receiver); + } + } + for (Phi phi : block.getPhis()) { + int receiver = phi.getReceiver().getIndex(); + int sourceVar = phiUpdater.getSourceVariable(receiver); + if (sourceVar >= 0) { + varMap.put(sourceVar, receiver); + } + } + + result[node] = new IntIntOpenHashMap(varMap); + + for (Instruction insn : block.getInstructions()) { + insn.acceptVisitor(defExtractor); + for (Variable definedVar : defExtractor.getDefinedVariables()) { + int sourceVar = phiUpdater.getSourceVariable(definedVar.getIndex()); + if (sourceVar >= 0) { + varMap.put(sourceVar, definedVar.getIndex()); + } + } + } + + for (int successor : dom.outgoingEdges(node)) { + stack[top++] = new Step(successor, new IntIntOpenHashMap(varMap)); + } + } + + return result; + } + private static Variable[] applySignature(Program program, ValueType[] arguments) { if (program.variableCount() == 0) { return new Variable[0]; diff --git a/core/src/main/java/org/teavm/parsing/ProgramParser.java b/core/src/main/java/org/teavm/parsing/ProgramParser.java index 831866e47..a6fb86437 100644 --- a/core/src/main/java/org/teavm/parsing/ProgramParser.java +++ b/core/src/main/java/org/teavm/parsing/ProgramParser.java @@ -23,10 +23,6 @@ import org.teavm.model.instructions.*; import org.teavm.model.util.InstructionTransitionExtractor; import org.teavm.model.util.ProgramUtils; -/** - * - * @author Alexey Andreev - */ public class ProgramParser { private static final byte ROOT = 0; private static final byte SINGLE = 1;