diff --git a/core/src/main/java/org/teavm/model/lowlevel/ClassInitializerTransformer.java b/core/src/main/java/org/teavm/model/lowlevel/ClassInitializerTransformer.java index 2a86b8edb..5721ea9f5 100644 --- a/core/src/main/java/org/teavm/model/lowlevel/ClassInitializerTransformer.java +++ b/core/src/main/java/org/teavm/model/lowlevel/ClassInitializerTransformer.java @@ -16,11 +16,10 @@ package org.teavm.model.lowlevel; import org.teavm.model.BasicBlock; -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.TextLocation; import org.teavm.model.ValueType; import org.teavm.model.Variable; import org.teavm.model.instructions.BranchingCondition; @@ -30,66 +29,55 @@ import org.teavm.model.instructions.InitClassInstruction; import org.teavm.model.instructions.InvocationType; import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.JumpInstruction; -import org.teavm.model.util.ProgramUtils; +import org.teavm.model.util.BasicBlockSplitter; import org.teavm.runtime.Allocator; public class ClassInitializerTransformer { public void transform(Program program) { - int[] basicBlockMap = new int[program.basicBlockCount()]; - for (int i = 0; i < basicBlockMap.length; ++i) { - basicBlockMap[i] = i; - } + BasicBlockSplitter splitter = new BasicBlockSplitter(program); - for (int i = 0; i < basicBlockMap.length; ++i) { - BasicBlock block = program.basicBlockAt(i); - for (Instruction instruction : block) { - if (!(instruction instanceof InitClassInstruction)) { - continue; - } - String className = ((InitClassInstruction) instruction).getClassName(); - block = instruction.getBasicBlock(); + int count = program.basicBlockCount(); + for (int i = 0; i < count; ++i) { + BasicBlock next = program.basicBlockAt(i); + BasicBlock block; + while (next != null) { + block = next; + next = null; + for (Instruction instruction : block) { + if (!(instruction instanceof InitClassInstruction)) { + continue; + } + String className = ((InitClassInstruction) instruction).getClassName(); - BasicBlock continueBlock = program.createBasicBlock(); - while (instruction.getNext() != null) { - Instruction toMove = instruction.getNext(); - toMove.delete(); - continueBlock.add(toMove); - } - continueBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program)); + BasicBlock continueBlock = splitter.split(block, instruction); - BasicBlock initBlock = program.createBasicBlock(); - instruction.delete(); - initBlock.add(instruction); - JumpInstruction jumpToContinue = new JumpInstruction(); - jumpToContinue.setTarget(continueBlock); - initBlock.add(jumpToContinue); + BasicBlock initBlock = program.createBasicBlock(); + instruction.delete(); + initBlock.add(instruction); + JumpInstruction jumpToContinue = new JumpInstruction(); + jumpToContinue.setTarget(continueBlock); + initBlock.add(jumpToContinue); - createInitCheck(program, block, className, continueBlock, initBlock); + createInitCheck(program, block, className, continueBlock, initBlock, instruction.getLocation()); - basicBlockMap[i] = continueBlock.getIndex(); - } - } - - for (int i = 0; i < basicBlockMap.length; ++i) { - BasicBlock block = program.basicBlockAt(i); - for (Phi phi : block.getPhis()) { - for (Incoming incoming : phi.getIncomings()) { - int source = incoming.getSource().getIndex(); - BasicBlock mappedSource = program.basicBlockAt(basicBlockMap[source]); - incoming.setSource(mappedSource); + next = continueBlock; + break; } } } + + splitter.fixProgram(); } private void createInitCheck(Program program, BasicBlock block, String className, BasicBlock continueBlock, - BasicBlock initBlock) { + BasicBlock initBlock, TextLocation location) { Variable clsVariable = program.createVariable(); Variable initializedVariable = program.createVariable(); ClassConstantInstruction clsConstant = new ClassConstantInstruction(); clsConstant.setReceiver(clsVariable); clsConstant.setConstant(ValueType.object(className)); + clsConstant.setLocation(location); block.add(clsConstant); InvokeInstruction checkInitialized = new InvokeInstruction(); @@ -97,12 +85,14 @@ public class ClassInitializerTransformer { checkInitialized.setMethod(new MethodReference(Allocator.class, "isInitialized", Class.class, boolean.class)); checkInitialized.setArguments(clsVariable); checkInitialized.setReceiver(initializedVariable); + checkInitialized.setLocation(location); block.add(checkInitialized); BranchingInstruction branching = new BranchingInstruction(BranchingCondition.NOT_EQUAL); branching.setOperand(initializedVariable); branching.setConsequent(continueBlock); branching.setAlternative(initBlock); + branching.setLocation(location); block.add(branching); } } diff --git a/core/src/main/java/org/teavm/model/lowlevel/ExceptionHandlingShadowStackContributor.java b/core/src/main/java/org/teavm/model/lowlevel/ExceptionHandlingShadowStackContributor.java index 540ed1f7e..6db4c50d9 100644 --- a/core/src/main/java/org/teavm/model/lowlevel/ExceptionHandlingShadowStackContributor.java +++ b/core/src/main/java/org/teavm/model/lowlevel/ExceptionHandlingShadowStackContributor.java @@ -16,6 +16,8 @@ package org.teavm.model.lowlevel; import com.carrotsearch.hppc.IntHashSet; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.carrotsearch.hppc.IntSet; import java.util.ArrayList; import java.util.Arrays; @@ -136,13 +138,15 @@ public class ExceptionHandlingShadowStackContributor { private int contributeToBasicBlock(BasicBlock block) { int[] currentJointSources = new int[program.variableCount()]; - int[] jointReceiverMap = new int[program.variableCount()]; + IntObjectMap jointReceiverMaps = new IntObjectHashMap<>(); Arrays.fill(currentJointSources, -1); - Arrays.fill(jointReceiverMap, -1); + IntSet outgoingVariablesToRemove = new IntHashSet(); IntSet variablesDefinedHere = new IntHashSet(); for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) { + int[] jointReceiverMap = new int[program.variableCount()]; + Arrays.fill(jointReceiverMap, -1); for (Phi phi : tryCatch.getHandler().getPhis()) { List sourceVariables = phi.getIncomings().stream() .filter(incoming -> incoming.getSource() == tryCatch.getProtectedBlock()) @@ -155,15 +159,20 @@ public class ExceptionHandlingShadowStackContributor { for (Variable sourceVar : sourceVariables) { BasicBlock sourceVarDefinedAt = variableDefinitionPlaces[sourceVar.getIndex()]; if (sourceVar.getIndex() < parameterCount - || dom.dominates(sourceVarDefinedAt.getIndex(), block.getIndex())) { + || (dom.dominates(sourceVarDefinedAt.getIndex(), block.getIndex()) + && block != sourceVarDefinedAt)) { currentJointSources[phi.getReceiver().getIndex()] = sourceVar.getIndex(); - break; + if (sourceVarDefinedAt != block) { + break; + } } } for (Variable sourceVar : sourceVariables) { jointReceiverMap[sourceVar.getIndex()] = phi.getReceiver().getIndex(); } } + + jointReceiverMaps.put(tryCatch.getHandler().getIndex(), jointReceiverMap); } DefinitionExtractor defExtractor = new DefinitionExtractor(); @@ -235,17 +244,19 @@ public class ExceptionHandlingShadowStackContributor { insn.acceptVisitor(defExtractor); for (Variable definedVar : defExtractor.getDefinedVariables()) { - int jointReceiver = jointReceiverMap[definedVar.getIndex()]; - if (jointReceiver >= 0) { - int formerVar = currentJointSources[jointReceiver]; - if (formerVar >= 0) { - if (variableDefinitionPlaces[formerVar] == initialBlock) { - outgoingVariablesToRemove.add(formerVar); + for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) { + int jointReceiver = jointReceiverMaps.get(tryCatch.getHandler().getIndex())[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()); } + variablesDefinedHere.add(definedVar.getIndex()); } }