Keep location stack in IR when inlining methods

This commit is contained in:
Alexey Andreev 2019-10-08 16:09:07 +03:00
parent c6f6125622
commit e762f26a40
14 changed files with 382 additions and 45 deletions

View File

@ -65,8 +65,7 @@ public final class LocationGraphBuilder {
for (int terminal : visitor.nodes) {
visitor.terminalNodes.set(terminal);
}
TextLocation[][] locations = propagate(visitor.locations.toArray(new TextLocation[0]), graph
);
TextLocation[][] locations = propagate(visitor.locations.toArray(new TextLocation[0]), graph);
Map<TextLocation, Set<TextLocation>> builder = new LinkedHashMap<>();
for (int i = 0; i < graph.size(); ++i) {
@ -353,7 +352,7 @@ public final class LocationGraphBuilder {
}
private void setLocation(TextLocation location) {
if (location == null) {
if (location == null || location.isEmpty()) {
return;
}
int node = createNode(location);

View File

@ -746,7 +746,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
}
private static SourceLocation map(TextLocation location) {
if (location == null) {
if (location == null || location.isEmpty()) {
return null;
}
return new SourceLocation(location.getFileName(), location.getLine());

View File

@ -153,6 +153,9 @@ public class DefaultNamingStrategy implements NamingStrategy {
String cls = fieldRef.getClassName();
while (cls != null) {
ClassReader clsReader = classSource.get(cls);
if (clsReader == null) {
break;
}
if (clsReader != null) {
FieldReader fieldReader = clsReader.getField(fieldRef.getFieldName());
if (fieldReader != null) {
@ -164,7 +167,7 @@ public class DefaultNamingStrategy implements NamingStrategy {
return fieldRef;
}
private final class Key {
static final class Key {
final MethodReference data;
int hash;
final byte classifier;

View File

@ -71,6 +71,7 @@ import org.teavm.ast.VariableNode;
import org.teavm.ast.WhileStatement;
import org.teavm.model.ElementModifier;
import org.teavm.model.FieldReference;
import org.teavm.model.InliningInfo;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
import org.teavm.model.ReferenceCache;
@ -89,6 +90,7 @@ public class AstIO {
private ReferenceCache referenceCache;
private TextLocation lastWrittenLocation;
private TextLocation lastReadLocation;
private InliningInfo lastReadInlining;
public AstIO(ReferenceCache referenceCache, SymbolTable symbolTable, SymbolTable fileTable,
SymbolTable variableTable) {
@ -99,7 +101,7 @@ public class AstIO {
}
public void write(VarDataOutput output, ControlFlowEntry[] cfg) throws IOException {
lastWrittenLocation = null;
lastWrittenLocation = TextLocation.EMPTY;
output.writeUnsigned(cfg.length);
for (ControlFlowEntry entry : cfg) {
writeLocation(output, entry.from);
@ -130,7 +132,7 @@ public class AstIO {
}
public ControlFlowEntry[] readControlFlow(VarDataInput input) throws IOException {
lastReadLocation = null;
lastReadLocation = TextLocation.EMPTY;
int size = input.readUnsigned();
ControlFlowEntry[] result = new ControlFlowEntry[size];
for (int i = 0; i < size; ++i) {
@ -152,7 +154,7 @@ public class AstIO {
for (int i = 0; i < varCount; ++i) {
node.getVariables().add(readVariable(input));
}
lastReadLocation = null;
lastReadLocation = TextLocation.EMPTY;
node.setBody(readStatement(input));
return node;
}
@ -211,23 +213,24 @@ public class AstIO {
}
private void writeLocation(VarDataOutput output, TextLocation location) throws IOException {
if (location == null || location.getFileName() == null) {
if (location == null) {
location = TextLocation.EMPTY;
}
if (location.isEmpty()) {
output.writeUnsigned(0);
lastWrittenLocation = null;
} else if (lastWrittenLocation != null && lastWrittenLocation.getFileName().equals(location.getFileName())) {
} else if (!lastWrittenLocation.isEmpty() && lastWrittenLocation.getFileName().equals(location.getFileName())) {
output.writeUnsigned(1);
output.writeSigned(location.getLine() - lastWrittenLocation.getLine());
lastWrittenLocation = location;
} else {
output.writeUnsigned(fileTable.lookup(location.getFileName()) + 2);
output.writeUnsigned(location.getLine());
lastWrittenLocation = location;
}
lastWrittenLocation = location;
}
private class NodeWriter implements ExprVisitor, StatementVisitor {
private final VarDataOutput output;
private TextLocation lastLocation;
private TextLocation lastLocation = TextLocation.EMPTY;
NodeWriter(VarDataOutput output) {
super();
@ -240,22 +243,52 @@ public class AstIO {
}
private void writeLocation(TextLocation location) throws IOException {
if (location == null) {
location = TextLocation.EMPTY;
}
if (Objects.equals(location, lastLocation)) {
return;
}
if (location == null || location.getFileName() == null) {
InliningInfo lastCommonInlining = null;
InliningInfo[] prevPath = lastLocation.getInliningPath();
InliningInfo[] newPath = location.getInliningPath();
int pathIndex = 0;
while (pathIndex < prevPath.length && pathIndex < newPath.length
&& prevPath[pathIndex].equals(newPath[pathIndex])) {
lastCommonInlining = prevPath[pathIndex++];
}
InliningInfo prevInlining = lastLocation.getInlining();
while (prevInlining != lastCommonInlining) {
output.writeUnsigned(124);
prevInlining = prevInlining.getParent();
}
while (pathIndex < newPath.length) {
InliningInfo inlining = newPath[pathIndex++];
MethodReference method = inlining.getMethod();
output.writeUnsigned(inlining.isEmpty() ? 122 : 123);
output.writeUnsigned(symbolTable.lookup(method.getClassName()));
output.writeUnsigned(symbolTable.lookup(method.getDescriptor().toString()));
if (!inlining.isEmpty()) {
output.writeUnsigned(fileTable.lookup(inlining.getFileName()));
output.writeUnsigned(inlining.getLine());
}
}
if (location.isEmpty()) {
output.writeUnsigned(127);
lastLocation = null;
} else if (lastLocation != null && lastLocation.getFileName().equals(location.getFileName())) {
} else if (!lastLocation.isEmpty() && lastLocation.getFileName().equals(location.getFileName())) {
output.writeUnsigned(126);
output.writeSigned(location.getLine() - lastLocation.getLine());
lastLocation = location;
} else {
output.writeUnsigned(125);
output.writeUnsigned(fileTable.lookup(location.getFileName()));
output.writeUnsigned(location.getLine());
lastLocation = location;
}
lastLocation = location;
}
private void writeSequence(List<Statement> sequence) throws IOException {
@ -702,10 +735,32 @@ public class AstIO {
break;
case 126:
lastReadLocation = new TextLocation(lastReadLocation.getFileName(),
lastReadLocation.getLine() + input.readSigned());
lastReadLocation.getLine() + input.readSigned(), lastReadInlining);
break;
case 125:
lastReadLocation = new TextLocation(fileTable.at(input.readUnsigned()), input.readUnsigned());
lastReadLocation = new TextLocation(fileTable.at(input.readUnsigned()), input.readUnsigned(),
lastReadInlining);
break;
case 122:
case 123: {
String className = symbolTable.at(input.readUnsigned());
MethodDescriptor methodDescriptor = MethodDescriptor.parse(symbolTable.at(input.readUnsigned()));
methodDescriptor = referenceCache.getCached(methodDescriptor);
String fileName;
int lineNumber;
if (type == 122) {
fileName = fileTable.at(input.readUnsigned());
lineNumber = input.readUnsigned();
} else {
fileName = null;
lineNumber = -1;
}
lastReadInlining = new InliningInfo(referenceCache.getCached(className, methodDescriptor),
fileName, lineNumber, lastReadInlining);
break;
}
case 124:
lastReadInlining = lastReadInlining.getParent();
break;
default:
return type;

View File

@ -24,6 +24,7 @@ import org.teavm.model.BasicBlockReader;
import org.teavm.model.FieldReference;
import org.teavm.model.Incoming;
import org.teavm.model.IncomingReader;
import org.teavm.model.InliningInfo;
import org.teavm.model.Instruction;
import org.teavm.model.InvokeDynamicInstruction;
import org.teavm.model.MethodDescriptor;
@ -206,6 +207,7 @@ public class ProgramIO {
block.getTryCatchBlocks().add(tryCatch);
}
InliningInfo inliningInfo = null;
TextLocation location = null;
insnLoop: while (true) {
int insnType = data.readUnsigned();
@ -213,19 +215,39 @@ public class ProgramIO {
case 0:
break insnLoop;
case 1:
location = null;
location = new TextLocation(null, -1, inliningInfo);
break;
case 2: {
String file = fileTable.at(data.readUnsigned());
int line = data.readUnsigned();
location = new TextLocation(file, line);
location = new TextLocation(file, line, inliningInfo);
break;
}
case 127: {
int line = location.getLine() + data.readSigned();
location = new TextLocation(location.getFileName(), line);
location = new TextLocation(location.getFileName(), line, inliningInfo);
break;
}
case 124:
case 125: {
String className = symbolTable.at(data.readUnsigned());
MethodDescriptor methodDescriptor = parseMethodDescriptor(symbolTable.at(data.readUnsigned()));
String fileName;
int lineNumber;
if (insnType == 125) {
fileName = fileTable.at(data.readUnsigned());
lineNumber = data.readUnsigned();
} else {
fileName = null;
lineNumber = -1;
}
inliningInfo = new InliningInfo(createMethodReference(className, methodDescriptor),
fileName, lineNumber, inliningInfo);
break;
}
case 126:
inliningInfo = inliningInfo.getParent();
break;
default: {
Instruction insn = readInstruction(insnType, program, data);
insn.setLocation(location);
@ -241,7 +263,7 @@ public class ProgramIO {
private class InstructionWriter implements InstructionReader {
private VarDataOutput output;
TextLocation location;
TextLocation location = TextLocation.EMPTY;
InstructionWriter(VarDataOutput output) {
this.output = output;
@ -250,11 +272,41 @@ public class ProgramIO {
@Override
public void location(TextLocation newLocation) {
try {
if (newLocation == null || newLocation.getFileName() == null || newLocation.getLine() < 0) {
if (newLocation == null) {
newLocation = TextLocation.EMPTY;
}
InliningInfo lastCommonInlining = null;
InliningInfo[] prevPath = location.getInliningPath();
InliningInfo[] newPath = newLocation.getInliningPath();
int pathIndex = 0;
while (pathIndex < prevPath.length && pathIndex < newPath.length
&& prevPath[pathIndex].equals(newPath[pathIndex])) {
lastCommonInlining = prevPath[pathIndex++];
}
InliningInfo prevInlining = location.getInlining();
while (prevInlining != lastCommonInlining) {
output.writeUnsigned(126);
prevInlining = prevInlining.getParent();
}
while (pathIndex < newPath.length) {
InliningInfo inlining = newPath[pathIndex++];
MethodReference method = inlining.getMethod();
output.writeUnsigned(inlining.isEmpty() ? 124 : 125);
output.writeUnsigned(symbolTable.lookup(method.getClassName()));
output.writeUnsigned(symbolTable.lookup(method.getDescriptor().toString()));
if (!inlining.isEmpty()) {
output.writeUnsigned(fileTable.lookup(inlining.getFileName()));
output.writeUnsigned(inlining.getLine());
}
}
if (newLocation.isEmpty()) {
output.writeUnsigned(1);
location = null;
} else {
if (location != null && location.getFileName().equals(newLocation.getFileName())) {
if (!location.isEmpty() && location.getFileName().equals(newLocation.getFileName())) {
output.writeUnsigned(127);
output.writeSigned(newLocation.getLine() - location.getLine());
} else {
@ -262,8 +314,8 @@ public class ProgramIO {
output.writeUnsigned(fileTable.lookup(newLocation.getFileName()));
output.writeUnsigned(newLocation.getLine());
}
location = newLocation;
}
location = newLocation;
} catch (IOException e) {
throw new IOExceptionWrapper(e);
}

View File

@ -348,7 +348,7 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
}
static class ClassMetadata {
int parentIndex;
int parentIndex = -1;
String jsName;
Map<Integer, Integer> fieldMap = new HashMap<>();
}

View File

@ -0,0 +1,84 @@
/*
* Copyright 2019 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.model;
import java.io.Serializable;
import java.util.Objects;
public class InliningInfo implements Serializable {
private MethodReference method;
private String fileName;
private int line;
private InliningInfo parent;
private transient int hash;
public InliningInfo(MethodReference method, String fileName, int line, InliningInfo parent) {
this.method = method;
this.fileName = fileName;
this.line = line;
this.parent = parent;
}
public MethodReference getMethod() {
return method;
}
public String getFileName() {
return fileName;
}
public int getLine() {
return line;
}
public InliningInfo getParent() {
return parent;
}
public boolean isEmpty() {
return fileName == null && line < 0;
}
@Override
public int hashCode() {
int result = hash;
if (result == 0) {
final int prime = 31;
result = 1;
result = prime * result + method.hashCode();
result = prime * result + (fileName == null ? 0 : fileName.hashCode());
result = prime * result + line;
result = prime * result + (parent != null ? parent.hashCode() : 0);
hash = result;
}
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof InliningInfo)) {
return false;
}
InliningInfo that = (InliningInfo) obj;
return Objects.equals(method, that.method)
&& Objects.equals(fileName, that.fileName)
&& line == that.line
&& Objects.equals(parent, that.parent);
}
}

View File

@ -19,12 +19,22 @@ import java.io.Serializable;
import java.util.Objects;
public class TextLocation implements Serializable {
public static final TextLocation EMPTY = new TextLocation(null, -1);
private static final InliningInfo[] EMPTY_ARRAY = new InliningInfo[0];
private String fileName;
private int line = -1;
private int line;
private InliningInfo inlining;
private transient int hash;
public TextLocation(String fileName, int line) {
this(fileName, line, null);
}
public TextLocation(String fileName, int line, InliningInfo inlining) {
this.fileName = fileName;
this.line = line;
this.inlining = inlining;
}
public String getFileName() {
@ -35,12 +45,47 @@ public class TextLocation implements Serializable {
return line;
}
public InliningInfo getInlining() {
return inlining;
}
public InliningInfo[] getInliningPath() {
if (inlining == null) {
return EMPTY_ARRAY;
}
InliningInfo inlining = this.inlining;
int sz = 0;
while (inlining != null) {
sz++;
inlining = inlining.getParent();
}
InliningInfo[] result = new InliningInfo[sz];
inlining = this.inlining;
while (inlining != null) {
result[--sz] = inlining;
inlining = inlining.getParent();
}
return result;
}
public boolean isEmpty() {
return fileName == null && line < 0;
}
@Override
public int hashCode() {
int result = hash;
if (result == 0) {
final int prime = 31;
int result = 1;
result = 1;
result = prime * result + (fileName == null ? 0 : fileName.hashCode());
result = prime * result + line;
result = prime * result + (inlining != null ? inlining.hashCode() : 0);
hash = result;
}
return result;
}
@ -53,11 +98,29 @@ public class TextLocation implements Serializable {
return false;
}
TextLocation other = (TextLocation) obj;
return Objects.equals(fileName, other.fileName) && line == other.line;
return Objects.equals(fileName, other.fileName) && line == other.line
&& Objects.equals(inlining, other.inlining);
}
@Override
public String toString() {
return fileName + ":" + line;
StringBuilder sb = new StringBuilder();
sb.append(fileName).append(':').append(line);
InliningInfo inlining = this.inlining;
if (inlining != null) {
sb.append('[');
boolean first = true;
while (inlining != null) {
if (!first) {
sb.append("->");
}
first = false;
sb.append(inlining.getMethod()).append("@")
.append(inlining.getFileName()).append(':').append(inlining.getLine());
inlining = inlining.getParent();
}
sb.append(']');
}
return sb.toString();
}
}

View File

@ -37,6 +37,7 @@ import org.teavm.model.ClassHierarchy;
import org.teavm.model.ClassReader;
import org.teavm.model.ElementModifier;
import org.teavm.model.Incoming;
import org.teavm.model.InliningInfo;
import org.teavm.model.Instruction;
import org.teavm.model.ListableClassReaderSource;
import org.teavm.model.MethodReader;
@ -44,6 +45,7 @@ import org.teavm.model.MethodReference;
import org.teavm.model.Phi;
import org.teavm.model.Program;
import org.teavm.model.ProgramReader;
import org.teavm.model.TextLocation;
import org.teavm.model.TryCatchBlock;
import org.teavm.model.VariableReader;
import org.teavm.model.analysis.ClassInference;
@ -178,7 +180,7 @@ public class Inlining {
if (step == null) {
return false;
}
List<PlanEntry> plan = buildPlan(program, -1, step, method);
List<PlanEntry> plan = buildPlan(program, -1, step, method, null);
if (plan.isEmpty()) {
return false;
}
@ -227,6 +229,8 @@ public class Inlining {
jumpToInlinedProgram.setTarget(firstInlineBlock);
block.add(jumpToInlinedProgram);
InliningInfoMerger inliningInfoMerger = new InliningInfoMerger(planEntry.locationInfo);
for (int i = 0; i < inlineProgram.basicBlockCount(); ++i) {
BasicBlock blockToInline = inlineProgram.basicBlockAt(i);
BasicBlock inlineBlock = program.basicBlockAt(firstInlineBlock.getIndex() + i);
@ -244,6 +248,14 @@ public class Inlining {
}
}
}
TextLocation location = insn.getLocation();
if (location == null) {
location = TextLocation.EMPTY;
}
location = new TextLocation(location.getFileName(), location.getLine(),
inliningInfoMerger.merge(location.getInlining()));
insn.setLocation(location);
}
List<Phi> phis = new ArrayList<>(blockToInline.getPhis());
@ -324,7 +336,8 @@ public class Inlining {
execPlan(program, planEntry.innerPlan, firstInlineBlock.getIndex());
}
private List<PlanEntry> buildPlan(Program program, int depth, InliningStep step, MethodReference method) {
private List<PlanEntry> buildPlan(Program program, int depth, InliningStep step, MethodReference method,
InliningInfo inliningInfo) {
List<PlanEntry> plan = new ArrayList<>();
int originalDepth = depth;
@ -373,13 +386,22 @@ public class Inlining {
}
Program invokedProgram = ProgramUtils.copy(invokedMethod.getProgram());
TextLocation location = insn.getLocation();
InliningInfo innerInliningInfo = new InliningInfo(
invoke.getMethod(),
location != null ? location.getFileName() : null,
location != null ? location.getLine() : -1,
inliningInfo);
PlanEntry entry = new PlanEntry();
entry.targetBlock = block.getIndex();
entry.targetInstruction = insn;
entry.program = invokedProgram;
entry.innerPlan.addAll(buildPlan(invokedProgram, depth + 1, innerStep, invokedMethod.getReference()));
entry.innerPlan.addAll(buildPlan(invokedProgram, depth + 1, innerStep, invokedMethod.getReference(),
inliningInfo));
entry.depth = depth;
entry.method = invokedMethod.getReference();
entry.locationInfo = innerInliningInfo;
plan.add(entry);
}
}
@ -441,6 +463,7 @@ public class Inlining {
Program program;
int depth;
final List<PlanEntry> innerPlan = new ArrayList<>();
InliningInfo locationInfo;
}
static class MethodUsageCounter extends AbstractInstructionReader {

View File

@ -0,0 +1,43 @@
/*
* Copyright 2019 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.model.optimization;
import java.util.HashMap;
import java.util.Map;
import org.teavm.model.InliningInfo;
class InliningInfoMerger {
private InliningInfo parent;
Map<InliningInfo, InliningInfo> inliningInfoCache = new HashMap<>();
InliningInfoMerger(InliningInfo parent) {
this.parent = parent;
}
InliningInfo merge(InliningInfo inliningInfo) {
if (inliningInfo == null) {
return parent;
}
InliningInfo result = inliningInfoCache.get(inliningInfo);
if (result == null) {
result = new InliningInfo(inliningInfo.getMethod(), inliningInfo.getFileName(), inliningInfo.getLine(),
merge(inliningInfo.getParent()));
inliningInfoCache.put(inliningInfo, result);
}
return result;
}
}

View File

@ -158,6 +158,11 @@ class InstructionStringifier implements InstructionReader {
}
private InstructionStringifier escapeIdentifierIfNeeded(String s) {
escapeIdentifierIfNeeded(sb, s);
return this;
}
static void escapeIdentifierIfNeeded(StringBuilder sb, String s) {
boolean needsEscaping = false;
if (s.isEmpty()) {
needsEscaping = true;
@ -176,8 +181,6 @@ class InstructionStringifier implements InstructionReader {
} else {
sb.append(s);
}
return this;
}
@Override

View File

@ -19,6 +19,7 @@ import java.util.List;
import java.util.Objects;
import org.teavm.model.BasicBlockReader;
import org.teavm.model.IncomingReader;
import org.teavm.model.InliningInfo;
import org.teavm.model.InstructionIterator;
import org.teavm.model.PhiReader;
import org.teavm.model.ProgramReader;
@ -76,13 +77,24 @@ public class ListingBuilder {
if (!Objects.equals(location, stringifier.getLocation())) {
location = stringifier.getLocation();
sb.append(prefix).append(" at ");
if (location == null) {
if (location == null || location.isEmpty()) {
sb.append("unknown location");
} else {
sb.append("'");
InstructionStringifier.escapeStringLiteral(location.getFileName(), sb);
sb.append("' " + location.getLine());
}
if (location != null) {
InliningInfo inliningInfo = location.getInlining();
while (inliningInfo != null) {
sb.append(" at ");
InstructionStringifier.escapeIdentifierIfNeeded(sb, inliningInfo.getMethod().toString());
sb.append(" '");
InstructionStringifier.escapeStringLiteral(inliningInfo.getFileName(), sb);
sb.append("' " + inliningInfo.getLine());
inliningInfo = inliningInfo.getParent();
}
}
sb.append('\n');
}
sb.append(prefix).append(" ").append(insnSb).append("\n");

View File

@ -332,7 +332,7 @@ public class ProgramParser {
BasicBlock basicBlock = null;
Map<Integer, String> accumulatedDebugNames = new HashMap<>();
Integer lastLineNumber = null;
TextLocation lastLocation = null;
TextLocation lastLocation = TextLocation.EMPTY;
for (int i = 0; i < basicBlocks.size(); ++i) {
BasicBlock newBasicBlock = basicBlocks.get(i);
if (newBasicBlock != null) {

View File

@ -37,7 +37,7 @@ interface TeaVMTestConfiguration<T extends TeaVMTarget> {
@Override
public void apply(TeaVM vm) {
vm.setOptimizationLevel(TeaVMOptimizationLevel.SIMPLE);
vm.setOptimizationLevel(TeaVMOptimizationLevel.FULL);
}
@Override