mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
C backend: fix more bugs, pass more tests
This commit is contained in:
parent
899725b6bd
commit
d2aa37d6a4
|
@ -767,12 +767,12 @@ public class ClassGenerator {
|
||||||
|
|
||||||
int lower = ranges.get(0).lower;
|
int lower = ranges.get(0).lower;
|
||||||
int upper = ranges.get(ranges.size() - 1).upper;
|
int upper = ranges.get(ranges.size() - 1).upper;
|
||||||
isSupertypeWriter.println("if (tag < " + lower + " || tag > " + upper + ") return INT32_C(0);");
|
isSupertypeWriter.println("if (tag < " + lower + " || tag >= " + upper + ") return INT32_C(0);");
|
||||||
|
|
||||||
for (int i = 1; i < ranges.size(); ++i) {
|
for (int i = 1; i < ranges.size(); ++i) {
|
||||||
lower = ranges.get(i - 1).upper;
|
lower = ranges.get(i - 1).upper;
|
||||||
upper = ranges.get(i).lower;
|
upper = ranges.get(i).lower;
|
||||||
isSupertypeWriter.println("if (tag < " + lower + " || tag > " + upper + ") return INT32_C(0);");
|
isSupertypeWriter.println("if (tag >= " + lower + " || tag < " + upper + ") return INT32_C(0);");
|
||||||
}
|
}
|
||||||
|
|
||||||
isSupertypeWriter.println("return INT32_C(1);");
|
isSupertypeWriter.println("return INT32_C(1);");
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.model.lowlevel;
|
package org.teavm.model.lowlevel;
|
||||||
|
|
||||||
|
import com.carrotsearch.hppc.IntHashSet;
|
||||||
|
import com.carrotsearch.hppc.IntSet;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -134,6 +136,9 @@ public class ExceptionHandlingShadowStackContributor {
|
||||||
int[] currentJointSources = new int[program.variableCount()];
|
int[] currentJointSources = new int[program.variableCount()];
|
||||||
int[] jointReceiverMap = new int[program.variableCount()];
|
int[] jointReceiverMap = new int[program.variableCount()];
|
||||||
Arrays.fill(currentJointSources, -1);
|
Arrays.fill(currentJointSources, -1);
|
||||||
|
Arrays.fill(jointReceiverMap, -1);
|
||||||
|
IntSet outgoingVariablesToRemove = new IntHashSet();
|
||||||
|
IntSet variablesDefinedHere = new IntHashSet();
|
||||||
|
|
||||||
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
|
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
|
||||||
for (Phi phi : tryCatch.getHandler().getPhis()) {
|
for (Phi phi : tryCatch.getHandler().getPhis()) {
|
||||||
|
@ -162,6 +167,7 @@ public class ExceptionHandlingShadowStackContributor {
|
||||||
DefinitionExtractor defExtractor = new DefinitionExtractor();
|
DefinitionExtractor defExtractor = new DefinitionExtractor();
|
||||||
List<BasicBlock> blocksToClearHandlers = new ArrayList<>();
|
List<BasicBlock> blocksToClearHandlers = new ArrayList<>();
|
||||||
blocksToClearHandlers.add(block);
|
blocksToClearHandlers.add(block);
|
||||||
|
BasicBlock initialBlock = block;
|
||||||
|
|
||||||
for (Instruction insn : block) {
|
for (Instruction insn : block) {
|
||||||
if (isCallInstruction(insn)) {
|
if (isCallInstruction(insn)) {
|
||||||
|
@ -210,7 +216,8 @@ public class ExceptionHandlingShadowStackContributor {
|
||||||
CallSiteDescriptor callSite = new CallSiteDescriptor(callSites.size(), location);
|
CallSiteDescriptor callSite = new CallSiteDescriptor(callSites.size(), location);
|
||||||
callSites.add(callSite);
|
callSites.add(callSite);
|
||||||
List<Instruction> pre = setLocation(getInstructionsBeforeCallSite(callSite), insn.getLocation());
|
List<Instruction> pre = setLocation(getInstructionsBeforeCallSite(callSite), insn.getLocation());
|
||||||
List<Instruction> post = getInstructionsAfterCallSite(block, next, callSite, currentJointSources);
|
List<Instruction> post = getInstructionsAfterCallSite(initialBlock, block, next, callSite,
|
||||||
|
currentJointSources, outgoingVariablesToRemove, variablesDefinedHere);
|
||||||
post = setLocation(post, insn.getLocation());
|
post = setLocation(post, insn.getLocation());
|
||||||
block.getLastInstruction().insertPreviousAll(pre);
|
block.getLastInstruction().insertPreviousAll(pre);
|
||||||
block.addAll(post);
|
block.addAll(post);
|
||||||
|
@ -220,15 +227,27 @@ public class ExceptionHandlingShadowStackContributor {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
block = next;
|
block = next;
|
||||||
|
outgoingVariablesToRemove.clear();
|
||||||
|
variablesDefinedHere.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
insn.acceptVisitor(defExtractor);
|
insn.acceptVisitor(defExtractor);
|
||||||
for (Variable definedVar : defExtractor.getDefinedVariables()) {
|
for (Variable definedVar : defExtractor.getDefinedVariables()) {
|
||||||
int jointReceiver = jointReceiverMap[definedVar.getIndex()];
|
int jointReceiver = jointReceiverMap[definedVar.getIndex()];
|
||||||
|
if (jointReceiver >= 0) {
|
||||||
|
int formerVar = currentJointSources[jointReceiver];
|
||||||
|
if (formerVar >= 0) {
|
||||||
|
if (variableDefinitionPlaces[formerVar] == initialBlock) {
|
||||||
|
outgoingVariablesToRemove.add(formerVar);
|
||||||
|
}
|
||||||
|
}
|
||||||
currentJointSources[jointReceiver] = definedVar.getIndex();
|
currentJointSources[jointReceiver] = definedVar.getIndex();
|
||||||
|
variablesDefinedHere.add(definedVar.getIndex());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fixOutgoingPhis(initialBlock, block, currentJointSources, outgoingVariablesToRemove, variablesDefinedHere);
|
||||||
for (BasicBlock blockToClear : blocksToClearHandlers) {
|
for (BasicBlock blockToClear : blocksToClearHandlers) {
|
||||||
blockToClear.getTryCatchBlocks().clear();
|
blockToClear.getTryCatchBlocks().clear();
|
||||||
}
|
}
|
||||||
|
@ -287,8 +306,9 @@ public class ExceptionHandlingShadowStackContributor {
|
||||||
return instructions;
|
return instructions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Instruction> getInstructionsAfterCallSite(BasicBlock block, BasicBlock next,
|
private List<Instruction> getInstructionsAfterCallSite(BasicBlock initialBlock, BasicBlock block, BasicBlock next,
|
||||||
CallSiteDescriptor callSite, int[] currentJointSources) {
|
CallSiteDescriptor callSite, int[] currentJointSources, IntSet outgoingVariablesToRemove,
|
||||||
|
IntSet variablesDefinedHere) {
|
||||||
Program program = block.getProgram();
|
Program program = block.getProgram();
|
||||||
List<Instruction> instructions = new ArrayList<>();
|
List<Instruction> instructions = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -325,20 +345,8 @@ public class ExceptionHandlingShadowStackContributor {
|
||||||
catchEntry.setCondition(handler.getId());
|
catchEntry.setCondition(handler.getId());
|
||||||
switchInsn.getEntries().add(catchEntry);
|
switchInsn.getEntries().add(catchEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Phi phi : tryCatch.getHandler().getPhis()) {
|
|
||||||
int value = currentJointSources[phi.getReceiver().getIndex()];
|
|
||||||
if (value < 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (Incoming incoming : phi.getIncomings()) {
|
|
||||||
if (incoming.getValue().getIndex() == value) {
|
|
||||||
incoming.setSource(block);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
fixOutgoingPhis(initialBlock, block, currentJointSources, outgoingVariablesToRemove, variablesDefinedHere);
|
||||||
|
|
||||||
if (!defaultExists) {
|
if (!defaultExists) {
|
||||||
switchInsn.setDefaultTarget(getDefaultExceptionHandler());
|
switchInsn.setDefaultTarget(getDefaultExceptionHandler());
|
||||||
|
@ -370,6 +378,41 @@ public class ExceptionHandlingShadowStackContributor {
|
||||||
return instructions;
|
return instructions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fixOutgoingPhis(BasicBlock block, BasicBlock newBlock, int[] currentJointSources,
|
||||||
|
IntSet outgoingVariablesToRemove, IntSet variablesDefinedHere) {
|
||||||
|
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
|
||||||
|
for (Phi phi : tryCatch.getHandler().getPhis()) {
|
||||||
|
int value = currentJointSources[phi.getReceiver().getIndex()];
|
||||||
|
if (value < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
List<Incoming> additionalIncomings = new ArrayList<>();
|
||||||
|
for (int i = 0; i < phi.getIncomings().size(); i++) {
|
||||||
|
Incoming incoming = phi.getIncomings().get(i);
|
||||||
|
if (incoming.getSource() != block) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (outgoingVariablesToRemove.contains(incoming.getValue().getIndex())) {
|
||||||
|
phi.getIncomings().remove(i--);
|
||||||
|
break;
|
||||||
|
} else if (incoming.getValue().getIndex() == value) {
|
||||||
|
if (variablesDefinedHere.contains(value)) {
|
||||||
|
incoming.setSource(newBlock);
|
||||||
|
} else {
|
||||||
|
Incoming incomingCopy = new Incoming();
|
||||||
|
incomingCopy.setSource(newBlock);
|
||||||
|
incomingCopy.setValue(incoming.getValue());
|
||||||
|
additionalIncomings.add(incomingCopy);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
phi.getIncomings().addAll(additionalIncomings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private BasicBlock getDefaultExceptionHandler() {
|
private BasicBlock getDefaultExceptionHandler() {
|
||||||
if (defaultExceptionHandler == null) {
|
if (defaultExceptionHandler == null) {
|
||||||
defaultExceptionHandler = program.createBasicBlock();
|
defaultExceptionHandler = program.createBasicBlock();
|
||||||
|
|
|
@ -16,10 +16,8 @@
|
||||||
package org.teavm.model.lowlevel;
|
package org.teavm.model.lowlevel;
|
||||||
|
|
||||||
import org.teavm.model.BasicBlock;
|
import org.teavm.model.BasicBlock;
|
||||||
import org.teavm.model.Incoming;
|
|
||||||
import org.teavm.model.Instruction;
|
import org.teavm.model.Instruction;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.Phi;
|
|
||||||
import org.teavm.model.Program;
|
import org.teavm.model.Program;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
import org.teavm.model.Variable;
|
import org.teavm.model.Variable;
|
||||||
|
@ -36,46 +34,29 @@ import org.teavm.model.instructions.JumpInstruction;
|
||||||
import org.teavm.model.instructions.LongConstantInstruction;
|
import org.teavm.model.instructions.LongConstantInstruction;
|
||||||
import org.teavm.model.instructions.NullCheckInstruction;
|
import org.teavm.model.instructions.NullCheckInstruction;
|
||||||
import org.teavm.model.instructions.NullConstantInstruction;
|
import org.teavm.model.instructions.NullConstantInstruction;
|
||||||
import org.teavm.model.optimization.RedundantJumpElimination;
|
import org.teavm.model.util.BasicBlockSplitter;
|
||||||
import org.teavm.model.util.ProgramUtils;
|
|
||||||
import org.teavm.runtime.ExceptionHandling;
|
import org.teavm.runtime.ExceptionHandling;
|
||||||
|
|
||||||
public class NullCheckTransformation {
|
public class NullCheckTransformation {
|
||||||
public void apply(Program program, ValueType returnType) {
|
public void apply(Program program, ValueType returnType) {
|
||||||
int[] mappings = new int[program.basicBlockCount()];
|
BasicBlockSplitter splitter = new BasicBlockSplitter(program);
|
||||||
for (int i = 0; i < mappings.length; ++i) {
|
|
||||||
mappings[i] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicBlock returnBlock = null;
|
BasicBlock returnBlock = null;
|
||||||
|
|
||||||
int count = program.basicBlockCount();
|
int count = program.basicBlockCount();
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
BasicBlock next = program.basicBlockAt(i);
|
BasicBlock next = program.basicBlockAt(i);
|
||||||
BasicBlock block = null;
|
BasicBlock block;
|
||||||
int newIndex = i;
|
|
||||||
while (next != null) {
|
while (next != null) {
|
||||||
block = next;
|
block = next;
|
||||||
newIndex = block.getIndex();
|
|
||||||
next = null;
|
next = null;
|
||||||
for (Instruction instruction : block) {
|
for (Instruction instruction : block) {
|
||||||
if (!(instruction instanceof NullCheckInstruction)) {
|
if (!(instruction instanceof NullCheckInstruction)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
NullCheckInstruction nullCheck = (NullCheckInstruction) instruction;
|
NullCheckInstruction nullCheck = (NullCheckInstruction) instruction;
|
||||||
|
BasicBlock continueBlock = splitter.split(block, nullCheck);
|
||||||
BasicBlock continueBlock = program.createBasicBlock();
|
|
||||||
|
|
||||||
continueBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
|
|
||||||
while (nullCheck.getNext() != null) {
|
|
||||||
Instruction nextInstruction = nullCheck.getNext();
|
|
||||||
nextInstruction.delete();
|
|
||||||
continueBlock.add(nextInstruction);
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicBlock throwBlock = program.createBasicBlock();
|
BasicBlock throwBlock = program.createBasicBlock();
|
||||||
|
|
||||||
throwBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
|
|
||||||
InvokeInstruction throwNPE = new InvokeInstruction();
|
InvokeInstruction throwNPE = new InvokeInstruction();
|
||||||
throwNPE.setType(InvocationType.SPECIAL);
|
throwNPE.setType(InvocationType.SPECIAL);
|
||||||
throwNPE.setMethod(new MethodReference(ExceptionHandling.class, "throwNullPointerException",
|
throwNPE.setMethod(new MethodReference(ExceptionHandling.class, "throwNullPointerException",
|
||||||
|
@ -109,8 +90,6 @@ public class NullCheckTransformation {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mappings[i] = newIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (returnBlock != null) {
|
if (returnBlock != null) {
|
||||||
|
@ -123,18 +102,7 @@ public class NullCheckTransformation {
|
||||||
returnBlock.add(fakeExit);
|
returnBlock.add(fakeExit);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (BasicBlock block : program.getBasicBlocks()) {
|
splitter.fixProgram();
|
||||||
for (Phi phi : block.getPhis()) {
|
|
||||||
for (Incoming incoming : phi.getIncomings()) {
|
|
||||||
int source = incoming.getSource().getIndex();
|
|
||||||
if (source < mappings.length && mappings[source] != source) {
|
|
||||||
incoming.setSource(program.basicBlockAt(mappings[source]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RedundantJumpElimination.optimize(program);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createFakeReturnValue(BasicBlock block, Variable variable, ValueType type) {
|
private void createFakeReturnValue(BasicBlock block, Variable variable, ValueType type) {
|
||||||
|
|
|
@ -38,6 +38,7 @@ public class ListingBuilder {
|
||||||
}
|
}
|
||||||
sb.append(prefix).append("var @").append(stringifier.getVariableLabel(i));
|
sb.append(prefix).append("var @").append(stringifier.getVariableLabel(i));
|
||||||
sb.append(" as ").append(var.getDebugName());
|
sb.append(" as ").append(var.getDebugName());
|
||||||
|
sb.append(" // " + var.getIndex());
|
||||||
sb.append('\n');
|
sb.append('\n');
|
||||||
}
|
}
|
||||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||||
|
|
188
core/src/main/java/org/teavm/model/util/BasicBlockSplitter.java
Normal file
188
core/src/main/java/org/teavm/model/util/BasicBlockSplitter.java
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 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.util;
|
||||||
|
|
||||||
|
import com.carrotsearch.hppc.ByteArrayList;
|
||||||
|
import com.carrotsearch.hppc.ByteIndexedContainer;
|
||||||
|
import com.carrotsearch.hppc.IntArrayList;
|
||||||
|
import com.carrotsearch.hppc.IntIndexedContainer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.teavm.model.BasicBlock;
|
||||||
|
import org.teavm.model.Incoming;
|
||||||
|
import org.teavm.model.Instruction;
|
||||||
|
import org.teavm.model.Phi;
|
||||||
|
import org.teavm.model.Program;
|
||||||
|
import org.teavm.model.Variable;
|
||||||
|
import org.teavm.model.optimization.RedundantJumpElimination;
|
||||||
|
|
||||||
|
public class BasicBlockSplitter {
|
||||||
|
private Program program;
|
||||||
|
private int[] mappings;
|
||||||
|
private IntIndexedContainer previousPtr;
|
||||||
|
private IntIndexedContainer firstPtr;
|
||||||
|
private ByteIndexedContainer isLastInSequence;
|
||||||
|
private BasicBlock[] variableDefinedAt;
|
||||||
|
|
||||||
|
public BasicBlockSplitter(Program program) {
|
||||||
|
this.program = program;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initIfNecessary() {
|
||||||
|
if (mappings != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mappings = new int[program.basicBlockCount()];
|
||||||
|
previousPtr = new IntArrayList(program.basicBlockCount() * 2);
|
||||||
|
firstPtr = new IntArrayList(program.basicBlockCount() * 2);
|
||||||
|
isLastInSequence = new ByteArrayList(program.basicBlockCount() * 2);
|
||||||
|
for (int i = 0; i < mappings.length; ++i) {
|
||||||
|
mappings[i] = i;
|
||||||
|
previousPtr.add(i);
|
||||||
|
firstPtr.add(i);
|
||||||
|
isLastInSequence.add((byte) 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
variableDefinedAt = ProgramUtils.getVariableDefinitionPlaces(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasicBlock split(BasicBlock block, Instruction afterInstruction) {
|
||||||
|
initIfNecessary();
|
||||||
|
|
||||||
|
if (afterInstruction.getBasicBlock() != block) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLastInSequence.get(block.getIndex()) == 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicBlock splitBlock = program.createBasicBlock();
|
||||||
|
while (previousPtr.size() < splitBlock.getIndex()) {
|
||||||
|
previousPtr.add(previousPtr.size());
|
||||||
|
firstPtr.add(firstPtr.size());
|
||||||
|
isLastInSequence.add((byte) 1);
|
||||||
|
}
|
||||||
|
isLastInSequence.set(block.getIndex(), (byte) 0);
|
||||||
|
previousPtr.add(block.getIndex());
|
||||||
|
firstPtr.add(firstPtr.get(block.getIndex()));
|
||||||
|
mappings[firstPtr.get(block.getIndex())] = splitBlock.getIndex();
|
||||||
|
isLastInSequence.add((byte) 1);
|
||||||
|
|
||||||
|
splitBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
|
||||||
|
while (afterInstruction.getNext() != null) {
|
||||||
|
Instruction nextInstruction = afterInstruction.getNext();
|
||||||
|
nextInstruction.delete();
|
||||||
|
splitBlock.add(nextInstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
return splitBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fixProgram() {
|
||||||
|
if (mappings == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BasicBlock block : program.getBasicBlocks()) {
|
||||||
|
Map<BasicBlock, List<Incoming>> incomingsBySource = new LinkedHashMap<>();
|
||||||
|
for (Phi phi : block.getPhis()) {
|
||||||
|
for (Incoming incoming : phi.getIncomings()) {
|
||||||
|
if (mappings[incoming.getSource().getIndex()] == incoming.getSource().getIndex()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
incomingsBySource.computeIfAbsent(incoming.getSource(), b -> new ArrayList<>()).add(incoming);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BasicBlock source : incomingsBySource.keySet()) {
|
||||||
|
boolean isExceptionHandler = source.getTryCatchBlocks().stream()
|
||||||
|
.anyMatch(tryCatch -> tryCatch.getHandler() == block);
|
||||||
|
if (isExceptionHandler) {
|
||||||
|
fixIncomingsInExceptionHandler(source, incomingsBySource.get(source));
|
||||||
|
} else {
|
||||||
|
BasicBlock newSource = program.basicBlockAt(mappings[source.getIndex()]);
|
||||||
|
for (Incoming incoming : incomingsBySource.get(source)) {
|
||||||
|
incoming.setSource(newSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RedundantJumpElimination.optimize(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fixIncomingsInExceptionHandler(BasicBlock source, List<Incoming> incomings) {
|
||||||
|
List<BasicBlock> sourceParts = buildBasicBlocksSequence(source);
|
||||||
|
assert sourceParts.get(0) == source;
|
||||||
|
Map<Variable, List<Incoming>> incomingsByValue = groupIncomingsByValue(incomings);
|
||||||
|
Map<Phi, Variable> lastDefinedValues = new HashMap<>();
|
||||||
|
|
||||||
|
for (Incoming incoming : incomings) {
|
||||||
|
if (variableDefinedAt[incoming.getValue().getIndex()] != source) {
|
||||||
|
lastDefinedValues.put(incoming.getPhi(), incoming.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DefinitionExtractor defExtractor = new DefinitionExtractor();
|
||||||
|
for (BasicBlock block : sourceParts) {
|
||||||
|
if (block != null) {
|
||||||
|
for (Map.Entry<Phi, Variable> lastDefinedEntry : lastDefinedValues.entrySet()) {
|
||||||
|
Incoming incomingCopy = new Incoming();
|
||||||
|
incomingCopy.setSource(block);
|
||||||
|
incomingCopy.setValue(lastDefinedEntry.getValue());
|
||||||
|
lastDefinedEntry.getKey().getIncomings().add(incomingCopy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Variable> definedVars = ProgramUtils.getVariablesDefinedInBlock(block, defExtractor);
|
||||||
|
for (Variable definedVar : definedVars) {
|
||||||
|
List<Incoming> incomingsOfDefinedVar = incomingsByValue.get(definedVar);
|
||||||
|
if (incomingsOfDefinedVar != null) {
|
||||||
|
for (Incoming incoming : incomingsOfDefinedVar) {
|
||||||
|
incoming.setSource(block);
|
||||||
|
lastDefinedValues.put(incoming.getPhi(), definedVar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<BasicBlock> buildBasicBlocksSequence(BasicBlock first) {
|
||||||
|
List<BasicBlock> result = new ArrayList<>(2);
|
||||||
|
BasicBlock block = program.basicBlockAt(mappings[first.getIndex()]);
|
||||||
|
while (previousPtr.get(block.getIndex()) != block.getIndex()) {
|
||||||
|
result.add(block);
|
||||||
|
block = program.basicBlockAt(previousPtr.get(block.getIndex()));
|
||||||
|
}
|
||||||
|
result.add(block);
|
||||||
|
Collections.reverse(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Variable, List<Incoming>> groupIncomingsByValue(List<Incoming> incomings) {
|
||||||
|
Map<Variable, List<Incoming>> incoingsByValue = new HashMap<>();
|
||||||
|
for (Incoming incoming : incomings) {
|
||||||
|
incoingsByValue.computeIfAbsent(incoming.getValue(), i -> new ArrayList<>()).add(incoming);
|
||||||
|
}
|
||||||
|
return incoingsByValue;
|
||||||
|
}
|
||||||
|
}
|
|
@ -228,4 +228,22 @@ public final class ProgramUtils {
|
||||||
|
|
||||||
return Arrays.asList(newNPE, initNPE, raise);
|
return Arrays.asList(newNPE, initNPE, raise);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<Variable> getVariablesDefinedInBlock(BasicBlock block, DefinitionExtractor defExtractor) {
|
||||||
|
List<Variable> varsDefinedInBlock = new ArrayList<>();
|
||||||
|
for (Phi phi : block.getPhis()) {
|
||||||
|
varsDefinedInBlock.add(phi.getReceiver());
|
||||||
|
}
|
||||||
|
if (block.getExceptionVariable() != null) {
|
||||||
|
varsDefinedInBlock.add(block.getExceptionVariable());
|
||||||
|
}
|
||||||
|
for (Instruction instruction : block) {
|
||||||
|
instruction.acceptVisitor(defExtractor);
|
||||||
|
Variable[] varsDefinedByInstruction = defExtractor.getDefinedVariables();
|
||||||
|
if (varsDefinedByInstruction != null) {
|
||||||
|
varsDefinedInBlock.addAll(Arrays.asList(varsDefinedByInstruction));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return varsDefinedInBlock;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,6 +150,8 @@ public class RegisterAllocator {
|
||||||
Program program = phi.getBasicBlock().getProgram();
|
Program program = phi.getBasicBlock().getProgram();
|
||||||
AssignInstruction copyInstruction = new AssignInstruction();
|
AssignInstruction copyInstruction = new AssignInstruction();
|
||||||
Variable firstCopy = program.createVariable();
|
Variable firstCopy = program.createVariable();
|
||||||
|
firstCopy.setLabel(phi.getReceiver().getLabel());
|
||||||
|
firstCopy.setDebugName(phi.getReceiver().getDebugName());
|
||||||
copyInstruction.setReceiver(firstCopy);
|
copyInstruction.setReceiver(firstCopy);
|
||||||
copyInstruction.setAssignee(incoming.getValue());
|
copyInstruction.setAssignee(incoming.getValue());
|
||||||
BasicBlock source = blockMap.get(incoming.getSource());
|
BasicBlock source = blockMap.get(incoming.getSource());
|
||||||
|
|
|
@ -476,7 +476,7 @@ public class OutputStreamWriterTest {
|
||||||
assertEquals("invalid conversion 4", "\u001b$B$($(\u001b(B", new String(bout.toByteArray(), "ISO8859_1"));
|
assertEquals("invalid conversion 4", "\u001b$B$($(\u001b(B", new String(bout.toByteArray(), "ISO8859_1"));
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
// Can't test missing converter
|
// Can't test missing converter
|
||||||
System.out.println(e);
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user