mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-23 00:24:11 -08:00
Add escape analysis
This commit is contained in:
parent
6781dd0abb
commit
e4fab2be41
|
@ -22,10 +22,6 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class GraphBuilder {
|
public class GraphBuilder {
|
||||||
private GraphImpl builtGraph;
|
private GraphImpl builtGraph;
|
||||||
private List<IntSet> addedEdges = new ArrayList<>();
|
private List<IntSet> addedEdges = new ArrayList<>();
|
||||||
|
|
367
core/src/main/java/org/teavm/model/analysis/EscapeAnalysis.java
Normal file
367
core/src/main/java/org/teavm/model/analysis/EscapeAnalysis.java
Normal file
|
@ -0,0 +1,367 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 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.analysis;
|
||||||
|
|
||||||
|
import com.carrotsearch.hppc.IntArrayDeque;
|
||||||
|
import com.carrotsearch.hppc.IntDeque;
|
||||||
|
import com.carrotsearch.hppc.IntOpenHashSet;
|
||||||
|
import com.carrotsearch.hppc.IntSet;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.BitSet;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.teavm.common.DisjointSet;
|
||||||
|
import org.teavm.common.Graph;
|
||||||
|
import org.teavm.common.GraphBuilder;
|
||||||
|
import org.teavm.model.BasicBlock;
|
||||||
|
import org.teavm.model.ClassReader;
|
||||||
|
import org.teavm.model.ClassReaderSource;
|
||||||
|
import org.teavm.model.FieldReader;
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.Incoming;
|
||||||
|
import org.teavm.model.Instruction;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.Phi;
|
||||||
|
import org.teavm.model.Program;
|
||||||
|
import org.teavm.model.TryCatchBlock;
|
||||||
|
import org.teavm.model.Variable;
|
||||||
|
import org.teavm.model.instructions.AbstractInstructionVisitor;
|
||||||
|
import org.teavm.model.instructions.AssignInstruction;
|
||||||
|
import org.teavm.model.instructions.BinaryBranchingInstruction;
|
||||||
|
import org.teavm.model.instructions.BranchingInstruction;
|
||||||
|
import org.teavm.model.instructions.CastInstruction;
|
||||||
|
import org.teavm.model.instructions.ClassConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.CloneArrayInstruction;
|
||||||
|
import org.teavm.model.instructions.ConstructInstruction;
|
||||||
|
import org.teavm.model.instructions.ExitInstruction;
|
||||||
|
import org.teavm.model.instructions.GetElementInstruction;
|
||||||
|
import org.teavm.model.instructions.GetFieldInstruction;
|
||||||
|
import org.teavm.model.instructions.InvokeInstruction;
|
||||||
|
import org.teavm.model.instructions.IsInstanceInstruction;
|
||||||
|
import org.teavm.model.instructions.MonitorEnterInstruction;
|
||||||
|
import org.teavm.model.instructions.MonitorExitInstruction;
|
||||||
|
import org.teavm.model.instructions.NullCheckInstruction;
|
||||||
|
import org.teavm.model.instructions.NullConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.PutElementInstruction;
|
||||||
|
import org.teavm.model.instructions.PutFieldInstruction;
|
||||||
|
import org.teavm.model.instructions.RaiseInstruction;
|
||||||
|
import org.teavm.model.instructions.StringConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.UnwrapArrayInstruction;
|
||||||
|
import org.teavm.model.util.InstructionTransitionExtractor;
|
||||||
|
import org.teavm.model.util.LivenessAnalyzer;
|
||||||
|
import org.teavm.model.util.UsageExtractor;
|
||||||
|
|
||||||
|
public class EscapeAnalysis {
|
||||||
|
private ClassReaderSource classSource;
|
||||||
|
private int[] definitionClasses;
|
||||||
|
private boolean[] escapingVars;
|
||||||
|
private FieldReference[][] fields;
|
||||||
|
|
||||||
|
public EscapeAnalysis(ClassReaderSource classSource) {
|
||||||
|
this.classSource = classSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void analyze(Program program, MethodReference methodReference) {
|
||||||
|
InstructionEscapeVisitor visitor = new InstructionEscapeVisitor(program.variableCount(), classSource);
|
||||||
|
for (int i = 0; i <= methodReference.parameterCount(); ++i) {
|
||||||
|
visitor.escapingVars[i] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BasicBlock block : program.getBasicBlocks()) {
|
||||||
|
for (Instruction insn : block) {
|
||||||
|
insn.acceptVisitor(visitor);
|
||||||
|
}
|
||||||
|
if (block.getExceptionVariable() != null) {
|
||||||
|
visitor.escapingVars[block.getExceptionVariable().getIndex()] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
definitionClasses = visitor.definitionClasses.pack(program.variableCount());
|
||||||
|
escapingVars = new boolean[program.variableCount()];
|
||||||
|
for (int i = 0; i < program.variableCount(); ++i) {
|
||||||
|
if (visitor.escapingVars[i]) {
|
||||||
|
escapingVars[definitionClasses[i]] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
analyzePhis(program);
|
||||||
|
|
||||||
|
fields = packFields(visitor.fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean escapes(int var) {
|
||||||
|
return escapingVars[definitionClasses[var]];
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldReference[] getFields(int var) {
|
||||||
|
FieldReference[] varFields = fields[definitionClasses[var]];
|
||||||
|
return varFields != null ? varFields.clone() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void analyzePhis(Program program) {
|
||||||
|
LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer();
|
||||||
|
livenessAnalyzer.analyze(program);
|
||||||
|
|
||||||
|
GraphBuilder graphBuilder = new GraphBuilder(program.variableCount());
|
||||||
|
IntDeque queue = new IntArrayDeque();
|
||||||
|
for (BasicBlock block : program.getBasicBlocks()) {
|
||||||
|
IntSet sharedIncomingVars = new IntOpenHashSet();
|
||||||
|
BitSet usedVars = getUsedVarsInBlock(livenessAnalyzer, block);
|
||||||
|
for (Phi phi : block.getPhis()) {
|
||||||
|
for (Incoming incoming : phi.getIncomings()) {
|
||||||
|
int var = incoming.getValue().getIndex();
|
||||||
|
graphBuilder.addEdge(var, phi.getReceiver().getIndex());
|
||||||
|
if (escapingVars[definitionClasses[var]] || !sharedIncomingVars.add(var) || usedVars.get(var)) {
|
||||||
|
queue.addLast(var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Graph graph = graphBuilder.build();
|
||||||
|
|
||||||
|
IntSet visited = new IntOpenHashSet();
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
int var = queue.removeFirst();
|
||||||
|
if (visited.add(var)) {
|
||||||
|
escapingVars[definitionClasses[var]] = true;
|
||||||
|
for (int successor : graph.outgoingEdges(var)) {
|
||||||
|
queue.addLast(successor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BitSet getUsedVarsInBlock(LivenessAnalyzer liveness, BasicBlock block) {
|
||||||
|
BitSet usedVars = new BitSet();
|
||||||
|
InstructionTransitionExtractor transitionExtractor = new InstructionTransitionExtractor();
|
||||||
|
block.getLastInstruction().acceptVisitor(transitionExtractor);
|
||||||
|
for (BasicBlock successor : transitionExtractor.getTargets()) {
|
||||||
|
usedVars.or(liveness.liveIn(successor.getIndex()));
|
||||||
|
}
|
||||||
|
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
|
||||||
|
usedVars.or(liveness.liveIn(tryCatch.getHandler().getIndex()));
|
||||||
|
}
|
||||||
|
|
||||||
|
UsageExtractor useExtractor = new UsageExtractor();
|
||||||
|
for (Instruction instruction : block) {
|
||||||
|
instruction.acceptVisitor(useExtractor);
|
||||||
|
for (Variable variable : useExtractor.getUsedVariables()) {
|
||||||
|
usedVars.set(variable.getIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return usedVars;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FieldReference[][] packFields(List<Set<FieldReference>> fields) {
|
||||||
|
List<Set<FieldReference>> joinedFields = new ArrayList<>(Collections.nCopies(fields.size(), null));
|
||||||
|
|
||||||
|
for (int i = 0; i < fields.size(); ++i) {
|
||||||
|
if (fields.get(i) == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int j = definitionClasses[i];
|
||||||
|
Set<FieldReference> fieldSet = joinedFields.get(j);
|
||||||
|
if (fieldSet == null) {
|
||||||
|
fieldSet = new LinkedHashSet<>();
|
||||||
|
joinedFields.set(j, fieldSet);
|
||||||
|
}
|
||||||
|
fieldSet.addAll(fields.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldReference[][] packedFields = new FieldReference[fields.size()][];
|
||||||
|
for (int i = 0; i < packedFields.length; ++i) {
|
||||||
|
if (joinedFields.get(i) != null) {
|
||||||
|
packedFields[i] = joinedFields.get(i).toArray(new FieldReference[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return packedFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class InstructionEscapeVisitor extends AbstractInstructionVisitor {
|
||||||
|
ClassReaderSource classSource;
|
||||||
|
DisjointSet definitionClasses;
|
||||||
|
boolean[] escapingVars;
|
||||||
|
List<Set<FieldReference>> fields;
|
||||||
|
|
||||||
|
public InstructionEscapeVisitor(int variableCount, ClassReaderSource classSource) {
|
||||||
|
this.classSource = classSource;
|
||||||
|
fields = new ArrayList<>(Collections.nCopies(variableCount, null));
|
||||||
|
definitionClasses = new DisjointSet();
|
||||||
|
for (int i = 0; i < variableCount; ++i) {
|
||||||
|
definitionClasses.create();
|
||||||
|
}
|
||||||
|
escapingVars = new boolean[variableCount];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ConstructInstruction insn) {
|
||||||
|
ClassReader cls = classSource.get(insn.getType());
|
||||||
|
if (cls == null) {
|
||||||
|
escapingVars[insn.getReceiver().getIndex()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (cls != null) {
|
||||||
|
for (FieldReader field : cls.getFields()) {
|
||||||
|
addField(insn.getReceiver(), field.getReference());
|
||||||
|
}
|
||||||
|
cls = cls.getParent() != null ? classSource.get(cls.getParent()) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(NullConstantInstruction insn) {
|
||||||
|
escapingVars[insn.getReceiver().getIndex()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ClassConstantInstruction insn) {
|
||||||
|
escapingVars[insn.getReceiver().getIndex()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(StringConstantInstruction insn) {
|
||||||
|
escapingVars[insn.getReceiver().getIndex()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(CloneArrayInstruction insn) {
|
||||||
|
escapingVars[insn.getArray().getIndex()] = true;
|
||||||
|
escapingVars[insn.getReceiver().getIndex()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(UnwrapArrayInstruction insn) {
|
||||||
|
definitionClasses.union(insn.getReceiver().getIndex(), insn.getArray().getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(AssignInstruction insn) {
|
||||||
|
definitionClasses.union(insn.getReceiver().getIndex(), insn.getAssignee().getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(CastInstruction insn) {
|
||||||
|
escapingVars[insn.getReceiver().getIndex()] = true;
|
||||||
|
escapingVars[insn.getValue().getIndex()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ExitInstruction insn) {
|
||||||
|
if (insn.getValueToReturn() != null) {
|
||||||
|
escapingVars[insn.getValueToReturn().getIndex()] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(RaiseInstruction insn) {
|
||||||
|
escapingVars[insn.getException().getIndex()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(GetFieldInstruction insn) {
|
||||||
|
escapingVars[insn.getReceiver().getIndex()] = true;
|
||||||
|
addField(insn.getInstance(), insn.getField());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(PutFieldInstruction insn) {
|
||||||
|
escapingVars[insn.getValue().getIndex()] = true;
|
||||||
|
addField(insn.getInstance(), insn.getField());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addField(Variable instance, FieldReference field) {
|
||||||
|
if (instance == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Set<FieldReference> fieldSet = fields.get(instance.getIndex());
|
||||||
|
if (fieldSet == null) {
|
||||||
|
fieldSet = new LinkedHashSet<>();
|
||||||
|
fields.set(instance.getIndex(), fieldSet);
|
||||||
|
}
|
||||||
|
fieldSet.add(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(GetElementInstruction insn) {
|
||||||
|
escapingVars[insn.getReceiver().getIndex()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(PutElementInstruction insn) {
|
||||||
|
escapingVars[insn.getValue().getIndex()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(InvokeInstruction insn) {
|
||||||
|
if (insn.getInstance() != null) {
|
||||||
|
escapingVars[insn.getInstance().getIndex()] = true;
|
||||||
|
}
|
||||||
|
for (Variable arg : insn.getArguments()) {
|
||||||
|
escapingVars[arg.getIndex()] = true;
|
||||||
|
}
|
||||||
|
if (insn.getReceiver() != null) {
|
||||||
|
escapingVars[insn.getReceiver().getIndex()] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(IsInstanceInstruction insn) {
|
||||||
|
escapingVars[insn.getValue().getIndex()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(NullCheckInstruction insn) {
|
||||||
|
definitionClasses.union(insn.getValue().getIndex(), insn.getReceiver().getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(MonitorEnterInstruction insn) {
|
||||||
|
escapingVars[insn.getObjectRef().getIndex()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(MonitorExitInstruction insn) {
|
||||||
|
escapingVars[insn.getObjectRef().getIndex()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(BranchingInstruction insn) {
|
||||||
|
switch (insn.getCondition()) {
|
||||||
|
case NULL:
|
||||||
|
case NOT_NULL:
|
||||||
|
escapingVars[insn.getOperand().getIndex()] = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(BinaryBranchingInstruction insn) {
|
||||||
|
switch (insn.getCondition()) {
|
||||||
|
case REFERENCE_EQUAL:
|
||||||
|
case REFERENCE_NOT_EQUAL:
|
||||||
|
escapingVars[insn.getFirstOperand().getIndex()] = true;
|
||||||
|
escapingVars[insn.getSecondOperand().getIndex()] = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,10 +18,6 @@ package org.teavm.model.instructions;
|
||||||
import org.teavm.model.Instruction;
|
import org.teavm.model.Instruction;
|
||||||
import org.teavm.model.Variable;
|
import org.teavm.model.Variable;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class NullConstantInstruction extends Instruction {
|
public class NullConstantInstruction extends Instruction {
|
||||||
private Variable receiver;
|
private Variable receiver;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,245 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 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.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.teavm.model.BasicBlock;
|
||||||
|
import org.teavm.model.ClassReaderSource;
|
||||||
|
import org.teavm.model.FieldReader;
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.Incoming;
|
||||||
|
import org.teavm.model.Instruction;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.Phi;
|
||||||
|
import org.teavm.model.Program;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.model.Variable;
|
||||||
|
import org.teavm.model.analysis.EscapeAnalysis;
|
||||||
|
import org.teavm.model.instructions.AbstractInstructionVisitor;
|
||||||
|
import org.teavm.model.instructions.AssignInstruction;
|
||||||
|
import org.teavm.model.instructions.ConstructInstruction;
|
||||||
|
import org.teavm.model.instructions.DoubleConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.FloatConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.GetFieldInstruction;
|
||||||
|
import org.teavm.model.instructions.IntegerConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.LongConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.NullConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.PutFieldInstruction;
|
||||||
|
import org.teavm.model.util.PhiUpdater;
|
||||||
|
|
||||||
|
public class ScalarReplacement implements MethodOptimization {
|
||||||
|
@Override
|
||||||
|
public boolean optimize(MethodOptimizationContext context, Program program) {
|
||||||
|
boolean changed = false;
|
||||||
|
while (performOnce(context, program)) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean performOnce(MethodOptimizationContext context, Program program) {
|
||||||
|
List<Map<FieldReference, Variable>> fieldMappings = new ArrayList<>(
|
||||||
|
Collections.nCopies(program.variableCount(), null));
|
||||||
|
|
||||||
|
MethodReference methodReference = context.getMethod().getReference();
|
||||||
|
EscapeAnalysis escapeAnalysis = new EscapeAnalysis(context.getClassSource());
|
||||||
|
escapeAnalysis.analyze(program, methodReference);
|
||||||
|
boolean canPerform = false;
|
||||||
|
for (int i = 0; i < fieldMappings.size(); ++i) {
|
||||||
|
FieldReference[] fields = escapeAnalysis.getFields(i);
|
||||||
|
if (!escapeAnalysis.escapes(i) && fields != null) {
|
||||||
|
Map<FieldReference, Variable> fieldMapping = new LinkedHashMap<>();
|
||||||
|
for (FieldReference field : fields) {
|
||||||
|
fieldMapping.put(field, program.createVariable());
|
||||||
|
}
|
||||||
|
fieldMappings.set(i, fieldMapping);
|
||||||
|
canPerform = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!canPerform) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScalarReplacementVisitor visitor = new ScalarReplacementVisitor(escapeAnalysis, context.getClassSource(),
|
||||||
|
fieldMappings);
|
||||||
|
for (BasicBlock block : program.getBasicBlocks()) {
|
||||||
|
for (Instruction instruction : block) {
|
||||||
|
instruction.acceptVisitor(visitor);
|
||||||
|
}
|
||||||
|
List<Phi> additionalPhis = new ArrayList<>();
|
||||||
|
for (int i = 0; i < block.getPhis().size(); ++i) {
|
||||||
|
Phi phi = block.getPhis().get(i);
|
||||||
|
if (escapeAnalysis.escapes(phi.getReceiver().getIndex())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldReference[] fields = escapeAnalysis.getFields(phi.getReceiver().getIndex());
|
||||||
|
if (fields == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FieldReference field : fields) {
|
||||||
|
boolean allIncomingsInitialized = true;
|
||||||
|
for (Incoming incoming : phi.getIncomings()) {
|
||||||
|
if (fieldMappings.get(incoming.getValue().getIndex()).get(field) == null) {
|
||||||
|
allIncomingsInitialized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allIncomingsInitialized) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Phi phiReplacement = new Phi();
|
||||||
|
phiReplacement.setReceiver(fieldMappings.get(phi.getReceiver().getIndex()).get(field));
|
||||||
|
|
||||||
|
for (Incoming incoming : phi.getIncomings()) {
|
||||||
|
Incoming incomingReplacement = new Incoming();
|
||||||
|
incomingReplacement.setSource(incoming.getSource());
|
||||||
|
incomingReplacement.setValue(fieldMappings.get(incoming.getValue().getIndex()).get(field));
|
||||||
|
phiReplacement.getIncomings().add(incomingReplacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
additionalPhis.add(phi);
|
||||||
|
}
|
||||||
|
block.getPhis().remove(i--);
|
||||||
|
}
|
||||||
|
block.getPhis().addAll(additionalPhis);
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable[] arguments = new Variable[methodReference.parameterCount() + 1];
|
||||||
|
for (int i = 0; i < arguments.length; ++i) {
|
||||||
|
arguments[i] = program.variableAt(i);
|
||||||
|
}
|
||||||
|
new PhiUpdater().updatePhis(program, arguments);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ScalarReplacementVisitor extends AbstractInstructionVisitor {
|
||||||
|
private EscapeAnalysis escapeAnalysis;
|
||||||
|
private ClassReaderSource classSource;
|
||||||
|
private List<Map<FieldReference, Variable>> fieldMappings;
|
||||||
|
|
||||||
|
public ScalarReplacementVisitor(EscapeAnalysis escapeAnalysis, ClassReaderSource classSource,
|
||||||
|
List<Map<FieldReference, Variable>> fieldMappings) {
|
||||||
|
this.escapeAnalysis = escapeAnalysis;
|
||||||
|
this.classSource = classSource;
|
||||||
|
this.fieldMappings = fieldMappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ConstructInstruction insn) {
|
||||||
|
int var = insn.getReceiver().getIndex();
|
||||||
|
if (!escapeAnalysis.escapes(var) && escapeAnalysis.getFields(var) != null) {
|
||||||
|
for (FieldReference fieldRef : escapeAnalysis.getFields(var)) {
|
||||||
|
FieldReader field = classSource.resolve(fieldRef);
|
||||||
|
Variable receiver = fieldMappings.get(insn.getReceiver().getIndex()).get(fieldRef);
|
||||||
|
Instruction initializer = generateDefaultValue(field.getType(), receiver);
|
||||||
|
initializer.setLocation(initializer.getLocation());
|
||||||
|
insn.insertPrevious(initializer);
|
||||||
|
}
|
||||||
|
insn.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(GetFieldInstruction insn) {
|
||||||
|
if (insn.getInstance() != null && !escapeAnalysis.escapes(insn.getInstance().getIndex())) {
|
||||||
|
Variable var = fieldMappings.get(insn.getInstance().getIndex()).get(insn.getField());
|
||||||
|
AssignInstruction assignment = new AssignInstruction();
|
||||||
|
assignment.setReceiver(insn.getReceiver());
|
||||||
|
assignment.setAssignee(var);
|
||||||
|
assignment.setLocation(insn.getLocation());
|
||||||
|
insn.replace(assignment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(PutFieldInstruction insn) {
|
||||||
|
if (insn.getInstance() != null && !escapeAnalysis.escapes(insn.getInstance().getIndex())) {
|
||||||
|
Variable var = fieldMappings.get(insn.getInstance().getIndex()).get(insn.getField());
|
||||||
|
AssignInstruction assignment = new AssignInstruction();
|
||||||
|
assignment.setReceiver(var);
|
||||||
|
assignment.setAssignee(insn.getValue());
|
||||||
|
assignment.setLocation(insn.getLocation());
|
||||||
|
insn.replace(assignment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(AssignInstruction insn) {
|
||||||
|
if (escapeAnalysis.escapes(insn.getAssignee().getIndex())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldReference[] fields = escapeAnalysis.getFields(insn.getReceiver().getIndex());
|
||||||
|
if (fields == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (FieldReference field : fields) {
|
||||||
|
Variable assignee = fieldMappings.get(insn.getAssignee().getIndex()).get(field);
|
||||||
|
if (assignee == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Variable receiver = fieldMappings.get(insn.getReceiver().getIndex()).get(field);
|
||||||
|
AssignInstruction assignment = new AssignInstruction();
|
||||||
|
assignment.setReceiver(receiver);
|
||||||
|
assignment.setAssignee(assignee);
|
||||||
|
assignment.setLocation(insn.getLocation());
|
||||||
|
insn.insertPrevious(assignment);
|
||||||
|
}
|
||||||
|
insn.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Instruction generateDefaultValue(ValueType type, Variable receiver) {
|
||||||
|
if (type instanceof ValueType.Primitive) {
|
||||||
|
switch (((ValueType.Primitive) type).getKind()) {
|
||||||
|
case BOOLEAN:
|
||||||
|
case BYTE:
|
||||||
|
case SHORT:
|
||||||
|
case CHARACTER:
|
||||||
|
case INTEGER: {
|
||||||
|
IntegerConstantInstruction insn = new IntegerConstantInstruction();
|
||||||
|
insn.setReceiver(receiver);
|
||||||
|
return insn;
|
||||||
|
}
|
||||||
|
case LONG: {
|
||||||
|
LongConstantInstruction insn = new LongConstantInstruction();
|
||||||
|
insn.setReceiver(receiver);
|
||||||
|
return insn;
|
||||||
|
}
|
||||||
|
case FLOAT: {
|
||||||
|
FloatConstantInstruction insn = new FloatConstantInstruction();
|
||||||
|
insn.setReceiver(receiver);
|
||||||
|
return insn;
|
||||||
|
}
|
||||||
|
case DOUBLE: {
|
||||||
|
DoubleConstantInstruction insn = new DoubleConstantInstruction();
|
||||||
|
insn.setReceiver(receiver);
|
||||||
|
return insn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NullConstantInstruction insn = new NullConstantInstruction();
|
||||||
|
insn.setReceiver(receiver);
|
||||||
|
return insn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -60,6 +60,7 @@ import org.teavm.model.optimization.LoopInvariantMotion;
|
||||||
import org.teavm.model.optimization.MethodOptimization;
|
import org.teavm.model.optimization.MethodOptimization;
|
||||||
import org.teavm.model.optimization.MethodOptimizationContext;
|
import org.teavm.model.optimization.MethodOptimizationContext;
|
||||||
import org.teavm.model.optimization.RedundantJumpElimination;
|
import org.teavm.model.optimization.RedundantJumpElimination;
|
||||||
|
import org.teavm.model.optimization.ScalarReplacement;
|
||||||
import org.teavm.model.optimization.UnreachableBasicBlockElimination;
|
import org.teavm.model.optimization.UnreachableBasicBlockElimination;
|
||||||
import org.teavm.model.optimization.UnusedVariableElimination;
|
import org.teavm.model.optimization.UnusedVariableElimination;
|
||||||
import org.teavm.model.text.ListingBuilder;
|
import org.teavm.model.text.ListingBuilder;
|
||||||
|
@ -551,6 +552,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
optimizations.add(new RedundantJumpElimination());
|
optimizations.add(new RedundantJumpElimination());
|
||||||
optimizations.add(new ArrayUnwrapMotion());
|
optimizations.add(new ArrayUnwrapMotion());
|
||||||
if (optimizationLevel.ordinal() >= TeaVMOptimizationLevel.ADVANCED.ordinal()) {
|
if (optimizationLevel.ordinal() >= TeaVMOptimizationLevel.ADVANCED.ordinal()) {
|
||||||
|
optimizations.add(new ScalarReplacement());
|
||||||
//optimizations.add(new LoopInversion());
|
//optimizations.add(new LoopInversion());
|
||||||
optimizations.add(new LoopInvariantMotion());
|
optimizations.add(new LoopInvariantMotion());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user