Store instructions as double-linked list instead of ArrayList

This commit is contained in:
Alexey Andreev 2016-12-09 00:07:58 +03:00
parent 231dcbaf36
commit ae5e1e4962
81 changed files with 807 additions and 866 deletions

View File

@ -22,10 +22,6 @@ import org.teavm.model.instructions.ExitInstruction;
import org.teavm.model.instructions.InvocationType; import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.InvokeInstruction;
/**
*
* @author Alexey Andreev
*/
public class JavacSupport implements ClassHolderTransformer { public class JavacSupport implements ClassHolderTransformer {
@Override @Override
public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) {
@ -39,15 +35,15 @@ public class JavacSupport implements ClassHolderTransformer {
ConstructInstruction construct = new ConstructInstruction(); ConstructInstruction construct = new ConstructInstruction();
construct.setReceiver(var); construct.setReceiver(var);
construct.setType("com.sun.tools.javac.api.JavacTool"); construct.setType("com.sun.tools.javac.api.JavacTool");
block.getInstructions().add(construct); block.add(construct);
InvokeInstruction init = new InvokeInstruction(); InvokeInstruction init = new InvokeInstruction();
init.setInstance(var); init.setInstance(var);
init.setType(InvocationType.SPECIAL); init.setType(InvocationType.SPECIAL);
init.setMethod(new MethodReference("com.sun.tools.javac.api.JavacTool", "<init>", ValueType.VOID)); init.setMethod(new MethodReference("com.sun.tools.javac.api.JavacTool", "<init>", ValueType.VOID));
block.getInstructions().add(init); block.add(init);
ExitInstruction exit = new ExitInstruction(); ExitInstruction exit = new ExitInstruction();
exit.setValueToReturn(var); exit.setValueToReturn(var);
block.getInstructions().add(exit); block.add(exit);
method.setProgram(program); method.setProgram(program);
} }
} }

View File

@ -1,6 +1,20 @@
/*
* Copyright 2016 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.classlib.impl; package org.teavm.classlib.impl;
import java.util.List;
import java.util.Properties; import java.util.Properties;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
@ -16,10 +30,6 @@ import org.teavm.model.instructions.ConstructInstruction;
import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.PutFieldInstruction; import org.teavm.model.instructions.PutFieldInstruction;
/**
*
* @author Alexey Andreev
*/
public class ScalaHacks implements ClassHolderTransformer { public class ScalaHacks implements ClassHolderTransformer {
private static final String ATTR_NAME_CLASS = "java.util.jar.Attributes$Name"; private static final String ATTR_NAME_CLASS = "java.util.jar.Attributes$Name";
@Override @Override
@ -56,16 +66,14 @@ public class ScalaHacks implements ClassHolderTransformer {
Program program = method.getProgram(); Program program = method.getProgram();
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
List<Instruction> instructions = block.getInstructions(); for (Instruction insn : block) {
for (int j = 0; j < instructions.size(); ++j) {
Instruction insn = instructions.get(j);
if (insn instanceof InvokeInstruction) { if (insn instanceof InvokeInstruction) {
if (((InvokeInstruction) insn).getMethod().getClassName().equals(ATTR_NAME_CLASS)) { if (((InvokeInstruction) insn).getMethod().getClassName().equals(ATTR_NAME_CLASS)) {
instructions.remove(j--); insn.delete();
} }
} else if (insn instanceof PutFieldInstruction) { } else if (insn instanceof PutFieldInstruction) {
if (((PutFieldInstruction) insn).getField().getFieldName().equals("ScalaCompilerVersion")) { if (((PutFieldInstruction) insn).getField().getFieldName().equals("ScalaCompilerVersion")) {
instructions.remove(j--); insn.delete();
} }
} else if (insn instanceof ConstructInstruction) { } else if (insn instanceof ConstructInstruction) {
ConstructInstruction cons = (ConstructInstruction) insn; ConstructInstruction cons = (ConstructInstruction) insn;

View File

@ -1,3 +1,18 @@
/*
* Copyright 2016 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.classlib.impl.lambda; package org.teavm.classlib.impl.lambda;
import java.util.Arrays; import java.util.Arrays;
@ -18,12 +33,8 @@ import org.teavm.model.ValueType;
import org.teavm.model.emit.ProgramEmitter; import org.teavm.model.emit.ProgramEmitter;
import org.teavm.model.emit.ValueEmitter; import org.teavm.model.emit.ValueEmitter;
/**
*
* @author Alexey Andreev
*/
public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor { public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor {
private int lambdaIndex = 0; private int lambdaIndex;
@Override @Override
public ValueEmitter substitute(DynamicCallSite callSite, ProgramEmitter callerPe) { public ValueEmitter substitute(DynamicCallSite callSite, ProgramEmitter callerPe) {

View File

@ -20,10 +20,6 @@ import org.teavm.classlib.java.io.TOutputStream;
import org.teavm.interop.DelegateTo; import org.teavm.interop.DelegateTo;
import org.teavm.platform.Platform; import org.teavm.platform.Platform;
/**
*
* @author Alexey Andreev
*/
class TConsoleOutputStreamStdout extends TOutputStream { class TConsoleOutputStreamStdout extends TOutputStream {
@Override @Override
@DelegateTo("writeLowLevel") @DelegateTo("writeLowLevel")

View File

@ -32,7 +32,7 @@ public class TInteger extends TNumber implements TComparable<TInteger> {
} }
public static String toString(int i, int radix) { public static String toString(int i, int radix) {
if (radix < MIN_VALUE || radix > MAX_VALUE) { if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
radix = 10; radix = 10;
} }
return new TAbstractStringBuilder(20).append(i, radix).toString(); return new TAbstractStringBuilder(20).append(i, radix).toString();

View File

@ -38,10 +38,6 @@ import org.teavm.model.emit.ProgramEmitter;
import org.teavm.model.emit.ValueEmitter; import org.teavm.model.emit.ValueEmitter;
import org.teavm.platform.PlatformAnnotationProvider; import org.teavm.platform.PlatformAnnotationProvider;
/**
*
* @author Alexey Andreev
*/
public class AnnotationDependencyListener extends AbstractDependencyListener { public class AnnotationDependencyListener extends AbstractDependencyListener {
@Override @Override
public void classReached(DependencyAgent agent, String className, CallLocation location) { public void classReached(DependencyAgent agent, String className, CallLocation location) {

View File

@ -351,7 +351,7 @@ public class Decompiler {
graph = ProgramUtils.buildControlFlowGraph(program); graph = ProgramUtils.buildControlFlowGraph(program);
int[] weights = new int[graph.size()]; int[] weights = new int[graph.size()];
for (int i = 0; i < weights.length; ++i) { for (int i = 0; i < weights.length; ++i) {
weights[i] = program.basicBlockAt(i).getInstructions().size(); weights[i] = program.basicBlockAt(i).instructionCount();
} }
int[] priorities = new int[graph.size()]; int[] priorities = new int[graph.size()];
for (int i = 0; i < targetBlocks.length; ++i) { for (int i = 0; i < targetBlocks.length; ++i) {
@ -447,9 +447,7 @@ public class Decompiler {
if (node >= 0) { if (node >= 0) {
generator.statements.clear(); generator.statements.clear();
TextLocation lastLocation = null; TextLocation lastLocation = null;
List<Instruction> instructions = generator.currentBlock.getInstructions(); for (Instruction insn : generator.currentBlock) {
for (int j = 0; j < instructions.size(); ++j) {
Instruction insn = generator.currentBlock.getInstructions().get(j);
if (insn.getLocation() != null && lastLocation != insn.getLocation()) { if (insn.getLocation() != null && lastLocation != insn.getLocation()) {
lastLocation = insn.getLocation(); lastLocation = insn.getLocation();
} }

View File

@ -21,6 +21,7 @@ import org.teavm.ast.AsyncMethodNode;
import org.teavm.ast.AsyncMethodPart; import org.teavm.ast.AsyncMethodPart;
import org.teavm.ast.RegularMethodNode; import org.teavm.ast.RegularMethodNode;
import org.teavm.common.Graph; import org.teavm.common.Graph;
import org.teavm.model.BasicBlock;
import org.teavm.model.Instruction; import org.teavm.model.Instruction;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.Variable; import org.teavm.model.Variable;
@ -107,7 +108,7 @@ public class Optimizer {
Program originalProgram = splitter.getOriginalProgram(); Program originalProgram = splitter.getOriginalProgram();
Program program = splitter.getProgram(partIndex); Program program = splitter.getProgram(partIndex);
int[] successors = splitter.getBlockSuccessors(partIndex); int[] successors = splitter.getBlockSuccessors(partIndex);
int[] splitPoints = splitter.getSplitPoints(partIndex); Instruction[] splitPoints = splitter.getSplitPoints(partIndex);
int[] originalBlocks = splitter.getOriginalBlocks(partIndex); int[] originalBlocks = splitter.getOriginalBlocks(partIndex);
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
@ -124,11 +125,11 @@ public class Optimizer {
// Remove from live set all variables that are defined in these blocks // Remove from live set all variables that are defined in these blocks
DefinitionExtractor defExtractor = new DefinitionExtractor(); DefinitionExtractor defExtractor = new DefinitionExtractor();
UsageExtractor useExtractor = new UsageExtractor(); UsageExtractor useExtractor = new UsageExtractor();
List<Instruction> instructions = originalProgram.basicBlockAt(originalBlocks[i]).getInstructions(); BasicBlock block = originalProgram.basicBlockAt(originalBlocks[i]);
int splitPoint = splitPoints[i]; Instruction splitPoint = splitPoints[i];
for (int j = instructions.size() - 1; j >= splitPoint; --j) { for (Instruction insn = block.getLastInstruction(); insn != splitPoint; insn = insn.getPrevious()) {
instructions.get(j).acceptVisitor(defExtractor); insn.acceptVisitor(defExtractor);
instructions.get(j).acceptVisitor(useExtractor); insn.acceptVisitor(useExtractor);
for (Variable var : defExtractor.getDefinedVariables()) { for (Variable var : defExtractor.getDefinedVariables()) {
liveVars.clear(var.getIndex()); liveVars.clear(var.getIndex());
} }

View File

@ -59,7 +59,7 @@ class ReadWriteStatsBuilder {
reads[block.getExceptionVariable().getIndex()]++; reads[block.getExceptionVariable().getIndex()]++;
} }
for (Instruction insn : block.getInstructions()) { for (Instruction insn : block) {
insn.acceptVisitor(defExtractor); insn.acceptVisitor(defExtractor);
insn.acceptVisitor(useExtractor); insn.acceptVisitor(useExtractor);
for (Variable var : defExtractor.getDefinedVariables()) { for (Variable var : defExtractor.getDefinedVariables()) {

View File

@ -336,24 +336,24 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
ConstructInstruction newExceptionInsn = new ConstructInstruction(); ConstructInstruction newExceptionInsn = new ConstructInstruction();
newExceptionInsn.setType(NoSuchMethodError.class.getName()); newExceptionInsn.setType(NoSuchMethodError.class.getName());
newExceptionInsn.setReceiver(exceptionVar); newExceptionInsn.setReceiver(exceptionVar);
block.getInstructions().add(newExceptionInsn); block.add(newExceptionInsn);
Variable constVar = program.createVariable(); Variable constVar = program.createVariable();
StringConstantInstruction constInsn = new StringConstantInstruction(); StringConstantInstruction constInsn = new StringConstantInstruction();
constInsn.setConstant("Native method implementation not found: " + method.getReference()); constInsn.setConstant("Native method implementation not found: " + method.getReference());
constInsn.setReceiver(constVar); constInsn.setReceiver(constVar);
block.getInstructions().add(constInsn); block.add(constInsn);
InvokeInstruction initExceptionInsn = new InvokeInstruction(); InvokeInstruction initExceptionInsn = new InvokeInstruction();
initExceptionInsn.setInstance(exceptionVar); initExceptionInsn.setInstance(exceptionVar);
initExceptionInsn.setMethod(new MethodReference(NoSuchMethodError.class, "<init>", String.class, void.class)); initExceptionInsn.setMethod(new MethodReference(NoSuchMethodError.class, "<init>", String.class, void.class));
initExceptionInsn.setType(InvocationType.SPECIAL); initExceptionInsn.setType(InvocationType.SPECIAL);
initExceptionInsn.getArguments().add(constVar); initExceptionInsn.getArguments().add(constVar);
block.getInstructions().add(initExceptionInsn); block.add(initExceptionInsn);
RaiseInstruction raiseInsn = new RaiseInstruction(); RaiseInstruction raiseInsn = new RaiseInstruction();
raiseInsn.setException(exceptionVar); raiseInsn.setException(exceptionVar);
block.getInstructions().add(raiseInsn); block.add(raiseInsn);
controller.getDiagnostics().error(new CallLocation(method.getReference()), controller.getDiagnostics().error(new CallLocation(method.getReference()),
"Native method {{m0}} has no implementation", method.getReference()); "Native method {{m0}} has no implementation", method.getReference());

View File

@ -37,8 +37,7 @@ public class NullPointerExceptionTransformer implements ClassHolderTransformer {
} }
private void transformBlock(BasicBlock block) { private void transformBlock(BasicBlock block) {
for (int i = 0; i < block.getInstructions().size(); ++i) { for (Instruction insn : block) {
Instruction insn = block.getInstructions().get(i);
if (insn instanceof InvokeInstruction) { if (insn instanceof InvokeInstruction) {
InvokeInstruction invoke = (InvokeInstruction) insn; InvokeInstruction invoke = (InvokeInstruction) insn;
if (invoke.getType() != InvocationType.VIRTUAL) { if (invoke.getType() != InvocationType.VIRTUAL) {
@ -49,7 +48,7 @@ public class NullPointerExceptionTransformer implements ClassHolderTransformer {
Variable var = block.getProgram().createVariable(); Variable var = block.getProgram().createVariable();
nullCheck.setReceiver(var); nullCheck.setReceiver(var);
invoke.setInstance(var); invoke.setInstance(var);
block.getInstructions().add(i++, nullCheck); insn.insertPrevious(nullCheck);
} }
} }
} }

View File

@ -267,7 +267,7 @@ public class WasmTarget implements TeaVMTarget {
BasicBlock entryBlock = program.basicBlockAt(0); BasicBlock entryBlock = program.basicBlockAt(0);
InitClassInstruction initInsn = new InitClassInstruction(); InitClassInstruction initInsn = new InitClassInstruction();
initInsn.setClassName(method.getOwnerName()); initInsn.setClassName(method.getOwnerName());
entryBlock.getInstructions().add(0, initInsn); entryBlock.addFirst(initInsn);
} }
classInitializerEliminator.apply(program); classInitializerEliminator.apply(program);
@ -689,7 +689,7 @@ public class WasmTarget implements TeaVMTarget {
} }
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) { for (Instruction insn : block) {
if (insn instanceof InvokeInstruction) { if (insn instanceof InvokeInstruction) {
InvokeInstruction invoke = (InvokeInstruction) insn; InvokeInstruction invoke = (InvokeInstruction) insn;
if (invoke.getType() == InvocationType.VIRTUAL) { if (invoke.getType() == InvocationType.VIRTUAL) {

View File

@ -45,8 +45,7 @@ public class ClassPatch implements ClassHolderTransformer {
private void patchProgram(Program program) { private void patchProgram(Program program) {
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
for (int j = 0; j < block.getInstructions().size(); ++j) { for (Instruction instruction : block) {
Instruction instruction = block.getInstructions().get(j);
if (instruction instanceof GetFieldInstruction) { if (instruction instanceof GetFieldInstruction) {
GetFieldInstruction getField = (GetFieldInstruction) instruction; GetFieldInstruction getField = (GetFieldInstruction) instruction;
if (getField.getField().equals(platformClassField)) { if (getField.getField().equals(platformClassField)) {
@ -54,14 +53,14 @@ public class ClassPatch implements ClassHolderTransformer {
replacement.setReceiver(getField.getReceiver()); replacement.setReceiver(getField.getReceiver());
replacement.setAssignee(getField.getInstance()); replacement.setAssignee(getField.getInstance());
replacement.setLocation(instruction.getLocation()); replacement.setLocation(instruction.getLocation());
block.getInstructions().set(j, replacement); instruction.replace(replacement);
} }
} else if (instruction instanceof PutFieldInstruction) { } else if (instruction instanceof PutFieldInstruction) {
PutFieldInstruction putField = (PutFieldInstruction) instruction; PutFieldInstruction putField = (PutFieldInstruction) instruction;
if (putField.getField().equals(platformClassField)) { if (putField.getField().equals(platformClassField)) {
EmptyInstruction replacement = new EmptyInstruction(); EmptyInstruction replacement = new EmptyInstruction();
replacement.setLocation(instruction.getLocation()); replacement.setLocation(instruction.getLocation());
block.getInstructions().set(j, replacement); instruction.replace(replacement);
} }
} }
} }

View File

@ -21,10 +21,6 @@ import org.teavm.model.*;
import org.teavm.model.instructions.*; import org.teavm.model.instructions.*;
import org.teavm.parsing.ClassDateProvider; import org.teavm.parsing.ClassDateProvider;
/**
*
* @author Alexey Andreev
*/
public class DiskProgramCache implements ProgramCache { public class DiskProgramCache implements ProgramCache {
private File directory; private File directory;
private ProgramIO programIO; private ProgramIO programIO;
@ -86,7 +82,7 @@ public class DiskProgramCache implements ProgramCache {
Program program = cache.get(method).program; Program program = cache.get(method).program;
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) { for (Instruction insn : block) {
insn.acceptVisitor(analyzer); insn.acceptVisitor(analyzer);
} }
} }

View File

@ -74,7 +74,7 @@ public class ProgramIO {
} }
TextLocation location = null; TextLocation location = null;
InstructionWriter insnWriter = new InstructionWriter(data); InstructionWriter insnWriter = new InstructionWriter(data);
for (Instruction insn : basicBlock.getInstructions()) { for (Instruction insn : basicBlock) {
try { try {
if (!Objects.equals(location, insn.getLocation())) { if (!Objects.equals(location, insn.getLocation())) {
location = insn.getLocation(); location = insn.getLocation();
@ -173,7 +173,7 @@ public class ProgramIO {
default: { default: {
Instruction insn = readInstruction(insnType, program, data); Instruction insn = readInstruction(insnType, program, data);
insn.setLocation(location); insn.setLocation(location);
block.getInstructions().add(insn); block.add(insn);
break; break;
} }
} }
@ -932,16 +932,20 @@ public class ProgramIO {
insn.setInstance(program.variableAt(input.readShort())); insn.setInstance(program.variableAt(input.readShort()));
String className = symbolTable.at(input.readInt()); String className = symbolTable.at(input.readInt());
String fieldName = symbolTable.at(input.readInt()); String fieldName = symbolTable.at(input.readInt());
ValueType type = ValueType.parse(symbolTable.at(input.readInt()));
insn.setField(new FieldReference(className, fieldName)); insn.setField(new FieldReference(className, fieldName));
insn.setValue(program.variableAt(input.readShort())); insn.setValue(program.variableAt(input.readShort()));
insn.setFieldType(type);
return insn; return insn;
} }
case 27: { case 27: {
PutFieldInstruction insn = new PutFieldInstruction(); PutFieldInstruction insn = new PutFieldInstruction();
String className = symbolTable.at(input.readInt()); String className = symbolTable.at(input.readInt());
String fieldName = symbolTable.at(input.readInt()); String fieldName = symbolTable.at(input.readInt());
ValueType type = ValueType.parse(symbolTable.at(input.readInt()));
insn.setField(new FieldReference(className, fieldName)); insn.setField(new FieldReference(className, fieldName));
insn.setValue(program.variableAt(input.readShort())); insn.setValue(program.variableAt(input.readShort()));
insn.setFieldType(type);
return insn; return insn;
} }
case 28: { case 28: {

View File

@ -21,10 +21,6 @@ import org.teavm.common.ServiceRepository;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.*; import org.teavm.model.*;
/**
*
* @author Alexey Andreev
*/
public class DependencyAgent implements DependencyInfo, ServiceRepository { public class DependencyAgent implements DependencyInfo, ServiceRepository {
private DependencyChecker checker; private DependencyChecker checker;

View File

@ -201,11 +201,12 @@ class DependencyGraphBuilder {
boolean hasIndy = false; boolean hasIndy = false;
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
for (int j = 0; j < block.getInstructions().size(); ++j) { for (Instruction insn : block) {
Instruction insn = block.getInstructions().get(j);
if (!(insn instanceof InvokeDynamicInstruction)) { if (!(insn instanceof InvokeDynamicInstruction)) {
continue; continue;
} }
block = insn.getBasicBlock();
InvokeDynamicInstruction indy = (InvokeDynamicInstruction) insn; InvokeDynamicInstruction indy = (InvokeDynamicInstruction) insn;
MethodReference bootstrapMethod = new MethodReference(indy.getBootstrapMethod().getClassName(), MethodReference bootstrapMethod = new MethodReference(indy.getBootstrapMethod().getClassName(),
indy.getBootstrapMethod().getName(), indy.getBootstrapMethod().signature()); indy.getBootstrapMethod().getName(), indy.getBootstrapMethod().signature());
@ -215,7 +216,7 @@ class DependencyGraphBuilder {
NullConstantInstruction nullInsn = new NullConstantInstruction(); NullConstantInstruction nullInsn = new NullConstantInstruction();
nullInsn.setReceiver(indy.getReceiver()); nullInsn.setReceiver(indy.getReceiver());
nullInsn.setLocation(indy.getLocation()); nullInsn.setLocation(indy.getLocation());
block.getInstructions().set(j, nullInsn); insn.replace(nullInsn);
CallLocation location = new CallLocation(caller.getMethod(), currentLocation); CallLocation location = new CallLocation(caller.getMethod(), currentLocation);
dependencyChecker.getDiagnostics().error(location, "Substitutor for bootstrap " dependencyChecker.getDiagnostics().error(location, "Substitutor for bootstrap "
+ "method {{m0}} was not found", bootstrapMethod); + "method {{m0}} was not found", bootstrapMethod);
@ -224,11 +225,11 @@ class DependencyGraphBuilder {
hasIndy = true; hasIndy = true;
BasicBlock splitBlock = program.createBasicBlock(); BasicBlock splitBlock = program.createBasicBlock();
List<Instruction> splitInstructions = block.getInstructions().subList(j + 1, while (insn.getNext() != null) {
block.getInstructions().size()); Instruction nextInsn = insn.getNext();
List<Instruction> splitInstructionsBackup = new ArrayList<>(splitInstructions); nextInsn.delete();
splitInstructions.clear(); splitBlock.add(nextInsn);
splitBlock.getInstructions().addAll(splitInstructionsBackup); }
for (int k = 0; k < program.basicBlockCount() - 1; ++k) { for (int k = 0; k < program.basicBlockCount() - 1; ++k) {
BasicBlock replaceBlock = program.basicBlockAt(k); BasicBlock replaceBlock = program.basicBlockAt(k);
@ -243,7 +244,7 @@ class DependencyGraphBuilder {
pe.enter(block); pe.enter(block);
pe.setCurrentLocation(indy.getLocation()); pe.setCurrentLocation(indy.getLocation());
block.getInstructions().remove(j); insn.delete();
List<ValueEmitter> arguments = new ArrayList<>(); List<ValueEmitter> arguments = new ArrayList<>();
for (int k = 0; k < indy.getArguments().size(); ++k) { for (int k = 0; k < indy.getArguments().size(); ++k) {

View File

@ -55,9 +55,7 @@ public class Linker {
Program program = method.getProgram(); Program program = method.getProgram();
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
for (int j = 0; j < block.getInstructions().size(); ++j) { for (Instruction insn : block) {
Instruction insn = block.getInstructions().get(j);
if (insn instanceof InvokeInstruction) { if (insn instanceof InvokeInstruction) {
InvokeInstruction invoke = (InvokeInstruction) insn; InvokeInstruction invoke = (InvokeInstruction) insn;
MethodDependencyInfo linkedMethod = dependency.getMethodImplementation(invoke.getMethod()); MethodDependencyInfo linkedMethod = dependency.getMethodImplementation(invoke.getMethod());
@ -75,7 +73,7 @@ public class Linker {
if (!fieldRef.getClassName().equals(method.getOwnerName())) { if (!fieldRef.getClassName().equals(method.getOwnerName())) {
InitClassInstruction initInsn = new InitClassInstruction(); InitClassInstruction initInsn = new InitClassInstruction();
initInsn.setClassName(fieldRef.getClassName()); initInsn.setClassName(fieldRef.getClassName());
block.getInstructions().add(j++, initInsn); insn.insertPrevious(initInsn);
} }
} else if (insn instanceof PutFieldInstruction) { } else if (insn instanceof PutFieldInstruction) {

View File

@ -18,10 +18,6 @@ package org.teavm.model;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/**
*
* @author Alexey Andreev
*/
public class AnnotationContainer implements AnnotationContainerReader { public class AnnotationContainer implements AnnotationContainerReader {
private Map<String, AnnotationHolder> annotations = new HashMap<>(); private Map<String, AnnotationHolder> annotations = new HashMap<>();

View File

@ -15,10 +15,6 @@
*/ */
package org.teavm.model; package org.teavm.model;
/**
*
* @author Alexey Andreev
*/
public interface AnnotationContainerReader { public interface AnnotationContainerReader {
AnnotationReader get(String type); AnnotationReader get(String type);

View File

@ -15,10 +15,6 @@
*/ */
package org.teavm.model; package org.teavm.model;
/**
*
* @author Alexey Andreev
*/
public interface AnnotationReader { public interface AnnotationReader {
String getType(); String getType();

View File

@ -18,10 +18,6 @@ package org.teavm.model;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
/**
*
* @author Alexey Andreev
*/
public class AnnotationValue { public class AnnotationValue {
public static final byte BOOLEAN = 0; public static final byte BOOLEAN = 0;
public static final byte BYTE = 1; public static final byte BYTE = 1;

View File

@ -18,14 +18,16 @@ package org.teavm.model;
import java.util.*; import java.util.*;
import org.teavm.model.instructions.InstructionReader; import org.teavm.model.instructions.InstructionReader;
public class BasicBlock implements BasicBlockReader { public class BasicBlock implements BasicBlockReader, Iterable<Instruction> {
private Program program; private Program program;
private int index; private int index;
private List<Phi> phis = new ArrayList<>(); private List<Phi> phis = new ArrayList<>();
private List<Instruction> instructions = new ArrayList<>();
private List<TryCatchBlock> tryCatchBlocks = new ArrayList<>(); private List<TryCatchBlock> tryCatchBlocks = new ArrayList<>();
private Variable exceptionVariable; private Variable exceptionVariable;
private String label; private String label;
Instruction firstInstruction;
Instruction lastInstruction;
int cachedSize;
BasicBlock(Program program, int index) { BasicBlock(Program program, int index) {
this.program = program; this.program = program;
@ -50,59 +52,114 @@ public class BasicBlock implements BasicBlockReader {
this.program = null; this.program = null;
} }
private List<Instruction> safeInstructions = new AbstractList<Instruction>() { public Instruction getFirstInstruction() {
@Override return firstInstruction;
public Instruction get(int index) {
return instructions.get(index);
}
@Override
public int size() {
return instructions.size();
}
@Override
public void add(int index, Instruction e) {
if (e.getBasicBlock() != null) {
throw new IllegalArgumentException("This instruction is in some basic block");
}
e.setBasicBlock(BasicBlock.this);
instructions.add(index, e);
}
@Override
public Instruction set(int index, Instruction element) {
if (element.getBasicBlock() != null) {
throw new IllegalArgumentException("This instruction is in some basic block");
}
Instruction oldInsn = instructions.get(index);
oldInsn.setBasicBlock(null);
element.setBasicBlock(BasicBlock.this);
return instructions.set(index, element);
}
@Override
public Instruction remove(int index) {
Instruction insn = instructions.remove(index);
insn.setBasicBlock(null);
return insn;
}
@Override
public void clear() {
for (Instruction insn : instructions) {
insn.setBasicBlock(null);
}
instructions.clear();
}
};
public List<Instruction> getInstructions() {
return safeInstructions;
} }
public Instruction getLastInstruction() { public Instruction getLastInstruction() {
return !instructions.isEmpty() ? instructions.get(instructions.size() - 1) : null; return lastInstruction;
}
@Override
public Iterator<Instruction> iterator() {
return new Iterator<Instruction>() {
Instruction instruction = firstInstruction;
private boolean removed;
@Override
public boolean hasNext() {
return instruction != null;
}
@Override
public Instruction next() {
if (instruction == null) {
throw new NoSuchElementException();
}
Instruction result = instruction;
instruction = instruction.next;
removed = false;
return result;
}
@Override
public void remove() {
if (removed) {
throw new IllegalStateException();
}
if (instruction == null) {
throw new NoSuchElementException();
}
Instruction next = instruction.next;
instruction.delete();
instruction = next;
removed = true;
}
};
}
public void addFirst(Instruction instruction) {
instruction.checkAddable();
if (firstInstruction == null) {
firstInstruction = instruction;
lastInstruction = instruction;
} else {
instruction.next = firstInstruction;
firstInstruction.previous = instruction;
firstInstruction = instruction;
}
cachedSize++;
instruction.basicBlock = this;
}
public void addAll(Iterable<Instruction> instructions) {
for (Instruction instruction : instructions) {
add(instruction);
}
}
public void add(Instruction instruction) {
instruction.checkAddable();
if (firstInstruction == null) {
firstInstruction = instruction;
lastInstruction = instruction;
} else {
instruction.previous = lastInstruction;
lastInstruction.next = instruction;
lastInstruction = instruction;
}
cachedSize++;
instruction.basicBlock = this;
}
public void addFirstAll(Iterable<Instruction> instructions) {
Iterator<Instruction> iterator = instructions.iterator();
if (!iterator.hasNext()) {
return;
}
Instruction last = iterator.next();
addFirst(last);
while (iterator.hasNext()) {
Instruction insn = iterator.next();
last.insertNext(insn);
last = insn;
}
}
public void removeAllInstructions() {
for (Instruction instruction = firstInstruction; instruction != null;) {
Instruction next = instruction.next;
instruction.previous = null;
instruction.next = null;
instruction.basicBlock = null;
instruction = next;
}
firstInstruction = null;
lastInstruction = null;
cachedSize = 0;
} }
private List<Phi> safePhis = new AbstractList<Phi>() { private List<Phi> safePhis = new AbstractList<Phi>() {
@ -165,21 +222,52 @@ public class BasicBlock implements BasicBlockReader {
@Override @Override
public int instructionCount() { public int instructionCount() {
return instructions.size(); return cachedSize;
} }
@Override @Override
public void readInstruction(int index, InstructionReader reader) { public InstructionIterator iterateInstructions() {
Instruction insn = instructions.get(index); return new InstructionIterator() {
reader.location(insn.getLocation()); Instruction instruction = firstInstruction;
insn.acceptVisitor(new InstructionReadVisitor(reader)); Instruction readInstruction;
InstructionReadVisitor visitor = new InstructionReadVisitor(null);
@Override
public boolean hasNext() {
return instruction != null;
}
@Override
public void next() {
readInstruction = instruction;
instruction = instruction.next;
}
@Override
public boolean hasPrevious() {
return instruction != null && instruction.previous != null;
}
@Override
public void previous() {
instruction = instruction.previous;
readInstruction = instruction;
}
@Override
public void read(InstructionReader reader) {
visitor.reader = reader;
readInstruction.acceptVisitor(visitor);
visitor.reader = null;
}
};
} }
@Override @Override
public void readAllInstructions(InstructionReader reader) { public void readAllInstructions(InstructionReader reader) {
InstructionReadVisitor visitor = new InstructionReadVisitor(reader); InstructionReadVisitor visitor = new InstructionReadVisitor(reader);
TextLocation location = null; TextLocation location = null;
for (Instruction insn : instructions) { for (Instruction insn : this) {
if (!Objects.equals(location, insn.getLocation())) { if (!Objects.equals(location, insn.getLocation())) {
location = insn.getLocation(); location = insn.getLocation();
reader.location(location); reader.location(location);

View File

@ -27,7 +27,7 @@ public interface BasicBlockReader {
int instructionCount(); int instructionCount();
void readInstruction(int index, InstructionReader reader); InstructionIterator iterateInstructions();
void readAllInstructions(InstructionReader reader); void readAllInstructions(InstructionReader reader);

View File

@ -15,15 +15,14 @@
*/ */
package org.teavm.model; package org.teavm.model;
import java.util.Iterator;
import org.teavm.model.instructions.InstructionVisitor; import org.teavm.model.instructions.InstructionVisitor;
public abstract class Instruction { public abstract class Instruction {
private BasicBlock basicBlock; BasicBlock basicBlock;
private TextLocation location; private TextLocation location;
Instruction next;
void setBasicBlock(BasicBlock basicBlock) { Instruction previous;
this.basicBlock = basicBlock;
}
public BasicBlock getBasicBlock() { public BasicBlock getBasicBlock() {
return basicBlock; return basicBlock;
@ -42,4 +41,127 @@ public abstract class Instruction {
} }
public abstract void acceptVisitor(InstructionVisitor visitor); public abstract void acceptVisitor(InstructionVisitor visitor);
public Instruction getNext() {
return next;
}
public Instruction getPrevious() {
return previous;
}
public boolean delete() {
if (basicBlock == null) {
return false;
}
if (next != null) {
next.previous = previous;
} else {
basicBlock.lastInstruction = previous;
}
if (previous != null) {
previous.next = next;
} else {
basicBlock.firstInstruction = next;
}
basicBlock.cachedSize--;
basicBlock = null;
next = null;
previous = null;
return true;
}
public boolean replace(Instruction other) {
checkInBasicBlock();
other.checkAddable();
if (next != null) {
next.previous = other;
} else {
basicBlock.lastInstruction = other;
}
other.next = next;
if (previous != null) {
previous.next = other;
} else {
basicBlock.firstInstruction = other;
}
other.previous = previous;
other.basicBlock = basicBlock;
basicBlock = null;
next = null;
previous = null;
return true;
}
public void insertNext(Instruction other) {
checkInBasicBlock();
other.checkAddable();
if (next != null) {
next.previous = other;
} else {
basicBlock.lastInstruction = other;
}
other.next = next;
other.previous = this;
next = other;
basicBlock.cachedSize++;
other.basicBlock = basicBlock;
}
public void insertNextAll(Iterable<Instruction> other) {
Iterator<Instruction> iterator = other.iterator();
Instruction last = this;
while (iterator.hasNext()) {
Instruction insn = iterator.next();
last.insertNext(insn);
last = insn;
}
}
public void insertPrevious(Instruction other) {
checkInBasicBlock();
other.checkAddable();
if (previous != null) {
previous.next = other;
} else {
basicBlock.firstInstruction = other;
}
other.previous = previous;
other.next = this;
previous = other;
basicBlock.cachedSize++;
other.basicBlock = basicBlock;
}
public void insertPreviousAll(Iterable<Instruction> other) {
for (Instruction instruction : other) {
insertPrevious(instruction);
}
}
private void checkInBasicBlock() {
if (getBasicBlock() == null) {
throw new IllegalArgumentException("This instruction is not in basic block");
}
}
void checkAddable() {
if (getBasicBlock() != null) {
throw new IllegalArgumentException("This instruction is in some basic block");
}
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 Alexey Andreev. * Copyright 2016 Alexey Andreev.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,22 +15,16 @@
*/ */
package org.teavm.model; package org.teavm.model;
import java.util.HashSet; import org.teavm.model.instructions.InstructionReader;
import java.util.Set;
/** public interface InstructionIterator {
* boolean hasNext();
* @author Alexey Andreev
*/
public class AsyncInformation {
private Set<MethodReference> syncMethods = new HashSet<>();
private Set<MethodReference> asyncMethods = new HashSet<>();
public Set<MethodReference> getSyncMethods() { void next();
return syncMethods;
}
public Set<MethodReference> getAsyncMethods() { boolean hasPrevious();
return asyncMethods;
} void previous();
void read(InstructionReader reader);
} }

View File

@ -18,12 +18,8 @@ package org.teavm.model;
import java.util.Collections; import java.util.Collections;
import org.teavm.model.instructions.*; import org.teavm.model.instructions.*;
/** public class InstructionReadVisitor implements InstructionVisitor {
* InstructionReader reader;
* @author Alexey Andreev
*/
class InstructionReadVisitor implements InstructionVisitor {
private InstructionReader reader;
public InstructionReadVisitor(InstructionReader reader) { public InstructionReadVisitor(InstructionReader reader) {
this.reader = reader; this.reader = reader;

View File

@ -17,19 +17,13 @@ package org.teavm.model;
public class InterpretException extends Exception { public class InterpretException extends Exception {
private final BasicBlockReader block; private final BasicBlockReader block;
private final int index;
public InterpretException(BasicBlockReader block, int index, Throwable cause) { public InterpretException(BasicBlockReader block, Throwable cause) {
super(cause); super(cause);
this.block = block; this.block = block;
this.index = index;
} }
public BasicBlockReader getBlock() { public BasicBlockReader getBlock() {
return block; return block;
} }
public int getIndex() {
return index;
}
} }

View File

@ -66,14 +66,15 @@ public class Interpreter {
try { try {
while (true) { while (true) {
int instructionIndex = 0; InstructionIterator iterator = currentBlock.iterateInstructions();
try { try {
while (instructionIndex < currentBlock.instructionCount()) { while (iterator.hasNext()) {
currentBlock.readInstruction(instructionIndex++, reader); iterator.next();
iterator.read(reader);
} }
} catch (RuntimeException e) { } catch (RuntimeException e) {
if (!pickExceptionHandler(e)) { if (!pickExceptionHandler(e)) {
throw new InterpretException(currentBlock, instructionIndex, e); throw new InterpretException(currentBlock, e);
} }
} }
switch (state) { switch (state) {
@ -82,7 +83,7 @@ public class Interpreter {
} }
case THROWN: { case THROWN: {
Throwable ex = (Throwable) result; Throwable ex = (Throwable) result;
throw new InterpretException(currentBlock, currentBlock.instructionCount() - 1, ex); throw new InterpretException(currentBlock, ex);
} }
case EXECUTING: case EXECUTING:
break; break;

View File

@ -60,7 +60,6 @@ class NullnessInformationBuilder {
private PhiUpdater phiUpdater; private PhiUpdater phiUpdater;
private List<NullConstantInstruction> nullInstructions = new ArrayList<>(); private List<NullConstantInstruction> nullInstructions = new ArrayList<>();
private List<NullCheckInstruction> notNullInstructions = new ArrayList<>(); private List<NullCheckInstruction> notNullInstructions = new ArrayList<>();
private List<List<Instruction>> additionalInstructionsByBlock = new ArrayList<>();
private Graph assignmentGraph; private Graph assignmentGraph;
private int[] nullPredecessorsLeft; private int[] nullPredecessorsLeft;
private int[] notNullPredecessorsLeft; private int[] notNullPredecessorsLeft;
@ -90,14 +89,8 @@ class NullnessInformationBuilder {
} }
private void insertAdditionalVariables() { private void insertAdditionalVariables() {
for (int i = 0; i < program.basicBlockCount(); ++i) {
additionalInstructionsByBlock.add(new ArrayList<>());
}
NullExtensionVisitor ev = new NullExtensionVisitor(); NullExtensionVisitor ev = new NullExtensionVisitor();
for (BasicBlock block : program.getBasicBlocks()) { for (BasicBlock block : program.getBasicBlocks()) {
ev.currentBasicBlock = block;
Instruction lastInstruction = block.getLastInstruction(); Instruction lastInstruction = block.getLastInstruction();
if (lastInstruction instanceof BranchingInstruction) { if (lastInstruction instanceof BranchingInstruction) {
BranchingInstruction branching = (BranchingInstruction) lastInstruction; BranchingInstruction branching = (BranchingInstruction) lastInstruction;
@ -108,17 +101,12 @@ class NullnessInformationBuilder {
} }
} }
for (ev.index = 0; ev.index < block.getInstructions().size(); ++ev.index) { for (Instruction instruction = block.getFirstInstruction(); instruction != null;) {
Instruction instruction = block.getInstructions().get(ev.index); Instruction next = instruction.getNext();
instruction.acceptVisitor(ev); instruction.acceptVisitor(ev);
instruction = next;
} }
} }
for (int i = 0; i < program.basicBlockCount(); ++i) {
List<Instruction> additionalInstructions = additionalInstructionsByBlock.get(i);
program.basicBlockAt(i).getInstructions().addAll(0, additionalInstructions);
}
additionalInstructionsByBlock.clear();
} }
private void collectAdditionalVariables() { private void collectAdditionalVariables() {
@ -139,12 +127,12 @@ class NullnessInformationBuilder {
NullCheckInstruction notNullInstruction = new NullCheckInstruction(); NullCheckInstruction notNullInstruction = new NullCheckInstruction();
notNullInstruction.setValue(variable); notNullInstruction.setValue(variable);
notNullInstruction.setReceiver(variable); notNullInstruction.setReceiver(variable);
additionalInstructionsByBlock.get(notNullBlock.getIndex()).add(notNullInstruction); notNullBlock.addFirst(notNullInstruction);
notNullInstructions.add(notNullInstruction); notNullInstructions.add(notNullInstruction);
NullConstantInstruction nullInstruction = new NullConstantInstruction(); NullConstantInstruction nullInstruction = new NullConstantInstruction();
nullInstruction.setReceiver(variable); nullInstruction.setReceiver(variable);
additionalInstructionsByBlock.get(nullBlock.getIndex()).add(nullInstruction); nullBlock.addFirst(nullInstruction);
nullInstructions.add(nullInstruction); nullInstructions.add(nullInstruction);
} }
@ -164,7 +152,7 @@ class NullnessInformationBuilder {
} }
} }
for (Instruction instruction : block.getInstructions()) { for (Instruction instruction : block) {
if (instruction instanceof AssignInstruction) { if (instruction instanceof AssignInstruction) {
AssignInstruction assignment = (AssignInstruction) instruction; AssignInstruction assignment = (AssignInstruction) instruction;
builder.addEdge(assignment.getAssignee().getIndex(), assignment.getReceiver().getIndex()); builder.addEdge(assignment.getAssignee().getIndex(), assignment.getReceiver().getIndex());
@ -185,68 +173,65 @@ class NullnessInformationBuilder {
private void findKnownNullness() { private void findKnownNullness() {
for (BasicBlock block : program.getBasicBlocks()) { for (BasicBlock block : program.getBasicBlocks()) {
for (Instruction instruction : block.getInstructions()) { for (Instruction instruction : block) {
instruction.acceptVisitor(nullnessVisitor); instruction.acceptVisitor(nullnessVisitor);
} }
} }
} }
class NullExtensionVisitor extends AbstractInstructionVisitor { class NullExtensionVisitor extends AbstractInstructionVisitor {
int index;
BasicBlock currentBasicBlock;
@Override @Override
public void visit(GetFieldInstruction insn) { public void visit(GetFieldInstruction insn) {
if (insn.getInstance() != null) { if (insn.getInstance() != null) {
insertNotNullInstruction(insn.getInstance()); insertNotNullInstruction(insn, insn.getInstance());
} }
} }
@Override @Override
public void visit(PutFieldInstruction insn) { public void visit(PutFieldInstruction insn) {
if (insn.getInstance() != null) { if (insn.getInstance() != null) {
insertNotNullInstruction(insn.getInstance()); insertNotNullInstruction(insn, insn.getInstance());
} }
} }
@Override @Override
public void visit(ArrayLengthInstruction insn) { public void visit(ArrayLengthInstruction insn) {
insertNotNullInstruction(insn.getArray()); insertNotNullInstruction(insn, insn.getArray());
} }
@Override @Override
public void visit(CloneArrayInstruction insn) { public void visit(CloneArrayInstruction insn) {
insertNotNullInstruction(insn.getArray()); insertNotNullInstruction(insn, insn.getArray());
} }
@Override @Override
public void visit(UnwrapArrayInstruction insn) { public void visit(UnwrapArrayInstruction insn) {
insertNotNullInstruction(insn.getArray()); insertNotNullInstruction(insn, insn.getArray());
} }
@Override @Override
public void visit(InvokeInstruction insn) { public void visit(InvokeInstruction insn) {
if (insn.getInstance() != null) { if (insn.getInstance() != null) {
insertNotNullInstruction(insn.getInstance()); insertNotNullInstruction(insn, insn.getInstance());
} }
} }
@Override @Override
public void visit(MonitorEnterInstruction insn) { public void visit(MonitorEnterInstruction insn) {
insertNotNullInstruction(insn.getObjectRef()); insertNotNullInstruction(insn, insn.getObjectRef());
} }
@Override @Override
public void visit(MonitorExitInstruction insn) { public void visit(MonitorExitInstruction insn) {
insertNotNullInstruction(insn.getObjectRef()); insertNotNullInstruction(insn, insn.getObjectRef());
} }
private void insertNotNullInstruction(Variable var) { private void insertNotNullInstruction(Instruction currentInstruction, Variable var) {
NullCheckInstruction insn = new NullCheckInstruction(); NullCheckInstruction insn = new NullCheckInstruction();
insn.setReceiver(var); insn.setReceiver(var);
insn.setValue(var); insn.setValue(var);
notNullInstructions.add(insn); notNullInstructions.add(insn);
currentBasicBlock.getInstructions().add(++index, insn); currentInstruction.insertNext(insn);
} }
} }

View File

@ -48,10 +48,6 @@ import org.teavm.model.instructions.StringConstantInstruction;
import org.teavm.model.instructions.SwitchInstruction; import org.teavm.model.instructions.SwitchInstruction;
import org.teavm.model.util.InstructionTransitionExtractor; import org.teavm.model.util.InstructionTransitionExtractor;
/**
*
* @author Alexey Andreev
*/
public final class ProgramEmitter { public final class ProgramEmitter {
private Program program; private Program program;
private BasicBlock block; private BasicBlock block;
@ -388,7 +384,7 @@ public final class ProgramEmitter {
if (currentLocation != null) { if (currentLocation != null) {
insn.setLocation(currentLocation); insn.setLocation(currentLocation);
} }
block.getInstructions().add(insn); block.add(insn);
} }
public static ProgramEmitter create(MethodHolder method, ClassReaderSource classSource) { public static ProgramEmitter create(MethodHolder method, ClassReaderSource classSource) {
@ -404,7 +400,7 @@ public final class ProgramEmitter {
JumpInstruction insn = new JumpInstruction(); JumpInstruction insn = new JumpInstruction();
insn.setTarget(block); insn.setTarget(block);
zeroBlock.getInstructions().add(insn); zeroBlock.add(insn);
program.createVariable(); program.createVariable();
for (int i = 0; i < method.parameterCount(); ++i) { for (int i = 0; i < method.parameterCount(); ++i) {

View File

@ -22,10 +22,6 @@ import org.teavm.model.instructions.BranchingCondition;
import org.teavm.model.instructions.SwitchInstruction; import org.teavm.model.instructions.SwitchInstruction;
import org.teavm.model.instructions.SwitchTableEntry; import org.teavm.model.instructions.SwitchTableEntry;
/**
*
* @author Alexey Andreev
*/
public class StringChooseEmitter { public class StringChooseEmitter {
private ProgramEmitter pe; private ProgramEmitter pe;
private ValueEmitter testValue; private ValueEmitter testValue;
@ -78,7 +74,7 @@ public class StringChooseEmitter {
} }
public ProgramEmitter otherwise(FragmentEmitter fragment) { public ProgramEmitter otherwise(FragmentEmitter fragment) {
otherwiseBlock.getInstructions().clear(); otherwiseBlock.removeAllInstructions();
pe.enter(otherwiseBlock); pe.enter(otherwiseBlock);
pe.emitAndJump(fragment, joinBlock); pe.emitAndJump(fragment, joinBlock);
pe.enter(joinBlock); pe.enter(joinBlock);

View File

@ -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 ArrayLengthInstruction extends Instruction { public class ArrayLengthInstruction extends Instruction {
private Variable array; private Variable array;
private Variable receiver; private Variable receiver;

View File

@ -17,10 +17,6 @@ package org.teavm.model.instructions;
import org.teavm.model.Instruction; import org.teavm.model.Instruction;
/**
*
* @author Alexey Andreev
*/
public class EmptyInstruction extends Instruction { public class EmptyInstruction extends Instruction {
@Override @Override
public void acceptVisitor(InstructionVisitor visitor) { public void acceptVisitor(InstructionVisitor visitor) {

View File

@ -18,10 +18,6 @@ package org.teavm.model.instructions;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
import org.teavm.model.Instruction; import org.teavm.model.Instruction;
/**
*
* @author Alexey Andreev
*/
public class JumpInstruction extends Instruction { public class JumpInstruction extends Instruction {
private BasicBlock target; private BasicBlock target;

View File

@ -40,14 +40,10 @@ public class ClassInitializerEliminator {
public void apply(Program program) { public void apply(Program program) {
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
List<Instruction> instructions = block.getInstructions(); for (Instruction insn : block) {
for (int j = 0; j < instructions.size(); ++j) {
Instruction insn = instructions.get(j);
if (insn instanceof InitClassInstruction) { if (insn instanceof InitClassInstruction) {
if (!filter(((InitClassInstruction) insn).getClassName())) { if (!filter(((InitClassInstruction) insn).getClassName())) {
EmptyInstruction empty = new EmptyInstruction(); insn.delete();
empty.setLocation(insn.getLocation());
instructions.set(j, empty);
} }
} }
} }

View File

@ -15,8 +15,6 @@
*/ */
package org.teavm.model.lowlevel; package org.teavm.model.lowlevel;
import java.util.ArrayList;
import java.util.List;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
import org.teavm.model.Incoming; import org.teavm.model.Incoming;
import org.teavm.model.Instruction; import org.teavm.model.Instruction;
@ -44,33 +42,31 @@ public class ClassInitializerTransformer {
for (int i = 0; i < basicBlockMap.length; ++i) { for (int i = 0; i < basicBlockMap.length; ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
List<Instruction> instructions = block.getInstructions(); for (Instruction instruction : block) {
for (int j = 0; j < instructions.size(); ++j) { if (!(instruction instanceof InitClassInstruction)) {
Instruction instruction = instructions.get(j); continue;
if (instruction instanceof InitClassInstruction) { }
String className = ((InitClassInstruction) instruction).getClassName(); String className = ((InitClassInstruction) instruction).getClassName();
block = instruction.getBasicBlock();
BasicBlock continueBlock = program.createBasicBlock(); BasicBlock continueBlock = program.createBasicBlock();
List<Instruction> instructionsToMove = instructions.subList(j + 1, instructions.size()); while (instruction.getNext() != null) {
List<Instruction> instructionsToMoveCopy = new ArrayList<>(instructionsToMove); Instruction toMove = instruction.getNext();
instructionsToMove.clear(); toMove.delete();
continueBlock.getInstructions().addAll(instructionsToMoveCopy); continueBlock.add(toMove);
}
continueBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program)); continueBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
BasicBlock initBlock = program.createBasicBlock(); BasicBlock initBlock = program.createBasicBlock();
instructions.remove(j); instruction.delete();
initBlock.getInstructions().add(instruction); initBlock.add(instruction);
JumpInstruction jumpToContinue = new JumpInstruction(); JumpInstruction jumpToContinue = new JumpInstruction();
jumpToContinue.setTarget(continueBlock); jumpToContinue.setTarget(continueBlock);
initBlock.getInstructions().add(jumpToContinue); initBlock.add(jumpToContinue);
createInitCheck(program, block, className, continueBlock, initBlock); createInitCheck(program, block, className, continueBlock, initBlock);
basicBlockMap[i] = continueBlock.getIndex(); basicBlockMap[i] = continueBlock.getIndex();
block = continueBlock;
instructions = block.getInstructions();
j = 0;
}
} }
} }
@ -94,19 +90,19 @@ public class ClassInitializerTransformer {
ClassConstantInstruction clsConstant = new ClassConstantInstruction(); ClassConstantInstruction clsConstant = new ClassConstantInstruction();
clsConstant.setReceiver(clsVariable); clsConstant.setReceiver(clsVariable);
clsConstant.setConstant(ValueType.object(className)); clsConstant.setConstant(ValueType.object(className));
block.getInstructions().add(clsConstant); block.add(clsConstant);
InvokeInstruction checkInitialized = new InvokeInstruction(); InvokeInstruction checkInitialized = new InvokeInstruction();
checkInitialized.setType(InvocationType.SPECIAL); checkInitialized.setType(InvocationType.SPECIAL);
checkInitialized.setMethod(new MethodReference(Allocator.class, "isInitialized", Class.class, boolean.class)); checkInitialized.setMethod(new MethodReference(Allocator.class, "isInitialized", Class.class, boolean.class));
checkInitialized.getArguments().add(clsVariable); checkInitialized.getArguments().add(clsVariable);
checkInitialized.setReceiver(initializedVariable); checkInitialized.setReceiver(initializedVariable);
block.getInstructions().add(checkInitialized); block.add(checkInitialized);
BranchingInstruction branching = new BranchingInstruction(BranchingCondition.EQUAL); BranchingInstruction branching = new BranchingInstruction(BranchingCondition.EQUAL);
branching.setOperand(initializedVariable); branching.setOperand(initializedVariable);
branching.setConsequent(continueBlock); branching.setConsequent(continueBlock);
branching.setAlternative(initBlock); branching.setAlternative(initBlock);
block.getInstructions().add(branching); block.add(branching);
} }
} }

View File

@ -101,7 +101,7 @@ public class ExceptionHandlingShadowStackContributor {
catchCall.setMethod(new MethodReference(ExceptionHandling.class, "catchException", catchCall.setMethod(new MethodReference(ExceptionHandling.class, "catchException",
Throwable.class)); Throwable.class));
catchCall.setReceiver(block.getExceptionVariable()); catchCall.setReceiver(block.getExceptionVariable());
block.getInstructions().add(0, catchCall); block.addFirst(catchCall);
block.setExceptionVariable(null); block.setExceptionVariable(null);
} }
@ -123,8 +123,6 @@ public class ExceptionHandlingShadowStackContributor {
} }
private int contributeToBasicBlock(BasicBlock block) { private int contributeToBasicBlock(BasicBlock block) {
List<Instruction> instructions = block.getInstructions();
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);
@ -147,9 +145,7 @@ public class ExceptionHandlingShadowStackContributor {
List<BasicBlock> blocksToClearHandlers = new ArrayList<>(); List<BasicBlock> blocksToClearHandlers = new ArrayList<>();
blocksToClearHandlers.add(block); blocksToClearHandlers.add(block);
for (int i = 0; i < instructions.size(); ++i) { for (Instruction insn : block) {
Instruction insn = instructions.get(i);
if (isCallInstruction(insn)) { if (isCallInstruction(insn)) {
BasicBlock next; BasicBlock next;
boolean last = false; boolean last = false;
@ -160,21 +156,23 @@ public class ExceptionHandlingShadowStackContributor {
raise.setType(InvocationType.SPECIAL); raise.setType(InvocationType.SPECIAL);
raise.getArguments().add(((RaiseInstruction) insn).getException()); raise.getArguments().add(((RaiseInstruction) insn).getException());
raise.setLocation(insn.getLocation()); raise.setLocation(insn.getLocation());
instructions.set(i, raise); insn.replace(raise);
insn = raise;
next = null; next = null;
} else if (i < instructions.size() - 1 && instructions.get(i + 1) instanceof JumpInstruction) { } else if (insn.getNext() != null && insn.getNext() instanceof JumpInstruction) {
next = ((JumpInstruction) instructions.get(i + 1)).getTarget(); next = ((JumpInstruction) insn.getNext()).getTarget();
instructions.remove(i + 1); insn.getNext().delete();
last = true; last = true;
} else { } else {
next = program.createBasicBlock(); next = program.createBasicBlock();
next.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program)); next.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
blocksToClearHandlers.add(next); blocksToClearHandlers.add(next);
List<Instruction> remainingInstructions = instructions.subList(i + 1, instructions.size()); while (insn.getNext() != null) {
List<Instruction> instructionsToMove = new ArrayList<>(remainingInstructions); Instruction nextInsn = insn.getNext();
remainingInstructions.clear(); nextInsn.delete();
next.getInstructions().addAll(instructionsToMove); next.add(nextInsn);
}
} }
CallSiteDescriptor callSite = new CallSiteDescriptor(callSites.size()); CallSiteDescriptor callSite = new CallSiteDescriptor(callSites.size());
@ -182,16 +180,14 @@ public class ExceptionHandlingShadowStackContributor {
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(block, next, callSite, currentJointSources);
post = setLocation(post, insn.getLocation()); post = setLocation(post, insn.getLocation());
instructions.addAll(instructions.size() - 1, pre); insn.insertPreviousAll(pre);
instructions.addAll(post); insn.insertNextAll(post);
hasExceptionHandlers = true; hasExceptionHandlers = true;
if (next == null || last) { if (next == null || last) {
break; break;
} }
block = next; block = next;
instructions = block.getInstructions();
i = -1;
} }
insn.acceptVisitor(defExtractor); insn.acceptVisitor(defExtractor);
@ -323,10 +319,10 @@ public class ExceptionHandlingShadowStackContributor {
private BasicBlock getDefaultExceptionHandler() { private BasicBlock getDefaultExceptionHandler() {
if (defaultExceptionHandler == null) { if (defaultExceptionHandler == null) {
defaultExceptionHandler = program.createBasicBlock(); defaultExceptionHandler = program.createBasicBlock();
Variable result = createReturnValueInstructions(defaultExceptionHandler.getInstructions()); Variable result = createReturnValueInstructions(defaultExceptionHandler);
ExitInstruction exit = new ExitInstruction(); ExitInstruction exit = new ExitInstruction();
exit.setValueToReturn(result); exit.setValueToReturn(result);
defaultExceptionHandler.getInstructions().add(exit); defaultExceptionHandler.add(exit);
} }
return defaultExceptionHandler; return defaultExceptionHandler;
} }
@ -343,7 +339,7 @@ public class ExceptionHandlingShadowStackContributor {
return phi; return phi;
} }
private Variable createReturnValueInstructions(List<Instruction> instructions) { private Variable createReturnValueInstructions(BasicBlock block) {
ValueType returnType = method.getReturnType(); ValueType returnType = method.getReturnType();
if (returnType == ValueType.VOID) { if (returnType == ValueType.VOID) {
return null; return null;
@ -360,29 +356,29 @@ public class ExceptionHandlingShadowStackContributor {
case INTEGER: case INTEGER:
IntegerConstantInstruction intConstant = new IntegerConstantInstruction(); IntegerConstantInstruction intConstant = new IntegerConstantInstruction();
intConstant.setReceiver(variable); intConstant.setReceiver(variable);
instructions.add(intConstant); block.add(intConstant);
return variable; return variable;
case LONG: case LONG:
LongConstantInstruction longConstant = new LongConstantInstruction(); LongConstantInstruction longConstant = new LongConstantInstruction();
longConstant.setReceiver(variable); longConstant.setReceiver(variable);
instructions.add(longConstant); block.add(longConstant);
return variable; return variable;
case FLOAT: case FLOAT:
FloatConstantInstruction floatConstant = new FloatConstantInstruction(); FloatConstantInstruction floatConstant = new FloatConstantInstruction();
floatConstant.setReceiver(variable); floatConstant.setReceiver(variable);
instructions.add(floatConstant); block.add(floatConstant);
return variable; return variable;
case DOUBLE: case DOUBLE:
DoubleConstantInstruction doubleConstant = new DoubleConstantInstruction(); DoubleConstantInstruction doubleConstant = new DoubleConstantInstruction();
doubleConstant.setReceiver(variable); doubleConstant.setReceiver(variable);
instructions.add(doubleConstant); block.add(doubleConstant);
return variable; return variable;
} }
} }
NullConstantInstruction nullConstant = new NullConstantInstruction(); NullConstantInstruction nullConstant = new NullConstantInstruction();
nullConstant.setReceiver(variable); nullConstant.setReceiver(variable);
instructions.add(nullConstant); block.add(nullConstant);
return variable; return variable;
} }

View File

@ -16,15 +16,18 @@
package org.teavm.model.lowlevel; package org.teavm.model.lowlevel;
import com.carrotsearch.hppc.IntArrayList; import com.carrotsearch.hppc.IntArrayList;
import com.carrotsearch.hppc.IntObjectMap; import com.carrotsearch.hppc.ObjectIntMap;
import com.carrotsearch.hppc.IntObjectOpenHashMap; import com.carrotsearch.hppc.ObjectIntOpenHashMap;
import com.carrotsearch.hppc.cursors.ObjectCursor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.BitSet; import java.util.BitSet;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.teavm.common.DominatorTree; import org.teavm.common.DominatorTree;
import org.teavm.common.Graph; import org.teavm.common.Graph;
@ -64,7 +67,7 @@ public class GCShadowStackContributor {
} }
public int contribute(Program program, MethodReader method) { public int contribute(Program program, MethodReader method) {
List<IntObjectMap<BitSet>> liveInInformation = findCallSiteLiveIns(program, method); List<Map<Instruction, BitSet>> liveInInformation = findCallSiteLiveIns(program, method);
Graph interferenceGraph = buildInterferenceGraph(liveInInformation, program); Graph interferenceGraph = buildInterferenceGraph(liveInInformation, program);
boolean[] spilled = getAffectedVariables(liveInInformation, program); boolean[] spilled = getAffectedVariables(liveInInformation, program);
@ -93,7 +96,7 @@ public class GCShadowStackContributor {
findAutoSpilledPhis(spilled, destinationPhis, inputCount, autoSpilled, i); findAutoSpilledPhis(spilled, destinationPhis, inputCount, autoSpilled, i);
} }
List<IntObjectMap<int[]>> liveInStores = reduceGCRootStores(program, usedColors, liveInInformation, List<Map<Instruction, int[]>> liveInStores = reduceGCRootStores(program, usedColors, liveInInformation,
colors, autoSpilled); colors, autoSpilled);
putLiveInGCRoots(program, liveInStores); putLiveInGCRoots(program, liveInStores);
@ -119,11 +122,11 @@ public class GCShadowStackContributor {
} }
} }
private List<IntObjectMap<BitSet>> findCallSiteLiveIns(Program program, MethodReader method) { private List<Map<Instruction, BitSet>> findCallSiteLiveIns(Program program, MethodReader method) {
Graph cfg = ProgramUtils.buildControlFlowGraph(program); Graph cfg = ProgramUtils.buildControlFlowGraph(program);
TypeInferer typeInferer = new TypeInferer(); TypeInferer typeInferer = new TypeInferer();
typeInferer.inferTypes(program, method.getReference()); typeInferer.inferTypes(program, method.getReference());
List<IntObjectMap<BitSet>> liveInInformation = new ArrayList<>(); List<Map<Instruction, BitSet>> liveInInformation = new ArrayList<>();
LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer(); LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer();
livenessAnalyzer.analyze(program); livenessAnalyzer.analyze(program);
@ -132,14 +135,14 @@ public class GCShadowStackContributor {
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
IntObjectMap<BitSet> blockLiveIn = new IntObjectOpenHashMap<>(); Map<Instruction, BitSet> blockLiveIn = new HashMap<>();
liveInInformation.add(blockLiveIn); liveInInformation.add(blockLiveIn);
BitSet currentLiveOut = new BitSet(); BitSet currentLiveOut = new BitSet();
for (int successor : cfg.outgoingEdges(i)) { for (int successor : cfg.outgoingEdges(i)) {
currentLiveOut.or(livenessAnalyzer.liveIn(successor)); currentLiveOut.or(livenessAnalyzer.liveIn(successor));
} }
for (int j = block.getInstructions().size() - 1; j >= 0; --j) {
Instruction insn = block.getInstructions().get(j); for (Instruction insn = block.getLastInstruction(); insn != null; insn = insn.getPrevious()) {
insn.acceptVisitor(defExtractor); insn.acceptVisitor(defExtractor);
insn.acceptVisitor(useExtractor); insn.acceptVisitor(useExtractor);
for (Variable usedVar : useExtractor.getUsedVariables()) { for (Variable usedVar : useExtractor.getUsedVariables()) {
@ -164,7 +167,7 @@ public class GCShadowStackContributor {
} }
} }
csLiveIn.clear(0, method.parameterCount() + 1); csLiveIn.clear(0, method.parameterCount() + 1);
blockLiveIn.put(j, csLiveIn); blockLiveIn.put(insn, csLiveIn);
} }
} }
if (block.getExceptionVariable() != null) { if (block.getExceptionVariable() != null) {
@ -175,11 +178,10 @@ public class GCShadowStackContributor {
return liveInInformation; return liveInInformation;
} }
private Graph buildInterferenceGraph(List<IntObjectMap<BitSet>> liveInInformation, Program program) { private Graph buildInterferenceGraph(List<Map<Instruction, BitSet>> liveInInformation, Program program) {
GraphBuilder builder = new GraphBuilder(program.variableCount()); GraphBuilder builder = new GraphBuilder(program.variableCount());
for (IntObjectMap<BitSet> blockLiveIn : liveInInformation) { for (Map<Instruction, BitSet> blockLiveIn : liveInInformation) {
for (ObjectCursor<BitSet> callSiteLiveIn : blockLiveIn.values()) { for (BitSet liveVarsSet : blockLiveIn.values()) {
BitSet liveVarsSet = callSiteLiveIn.value;
IntArrayList liveVars = new IntArrayList(); IntArrayList liveVars = new IntArrayList();
for (int i = liveVarsSet.nextSetBit(0); i >= 0; i = liveVarsSet.nextSetBit(i + 1)) { for (int i = liveVarsSet.nextSetBit(0); i >= 0; i = liveVarsSet.nextSetBit(i + 1)) {
liveVars.add(i); liveVars.add(i);
@ -196,11 +198,10 @@ public class GCShadowStackContributor {
return builder.build(); return builder.build();
} }
private boolean[] getAffectedVariables(List<IntObjectMap<BitSet>> liveInInformation, Program program) { private boolean[] getAffectedVariables(List<Map<Instruction, BitSet>> liveInInformation, Program program) {
boolean[] affectedVariables = new boolean[program.variableCount()]; boolean[] affectedVariables = new boolean[program.variableCount()];
for (IntObjectMap<BitSet> blockLiveIn : liveInInformation) { for (Map<Instruction, BitSet> blockLiveIn : liveInInformation) {
for (ObjectCursor<BitSet> callSiteLiveIn : blockLiveIn.values()) { for (BitSet liveVarsSet : blockLiveIn.values()) {
BitSet liveVarsSet = callSiteLiveIn.value;
for (int i = liveVarsSet.nextSetBit(0); i >= 0; i = liveVarsSet.nextSetBit(i + 1)) { for (int i = liveVarsSet.nextSetBit(0); i >= 0; i = liveVarsSet.nextSetBit(i + 1)) {
affectedVariables[i] = true; affectedVariables[i] = true;
} }
@ -243,8 +244,8 @@ public class GCShadowStackContributor {
return inputCount; return inputCount;
} }
private List<IntObjectMap<int[]>> reduceGCRootStores(Program program, int usedColors, private List<Map<Instruction, int[]>> reduceGCRootStores(Program program, int usedColors,
List<IntObjectMap<BitSet>> liveInInformation, int[] colors, boolean[] autoSpilled) { List<Map<Instruction, BitSet>> liveInInformation, int[] colors, boolean[] autoSpilled) {
class Step { class Step {
private final int node; private final int node;
private final int[] slotStates = new int[usedColors]; private final int[] slotStates = new int[usedColors];
@ -253,9 +254,9 @@ public class GCShadowStackContributor {
} }
} }
List<IntObjectMap<int[]>> slotsToUpdate = new ArrayList<>(); List<Map<Instruction, int[]>> slotsToUpdate = new ArrayList<>();
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
slotsToUpdate.add(new IntObjectOpenHashMap<>()); slotsToUpdate.add(new HashMap<>());
} }
Graph cfg = ProgramUtils.buildControlFlowGraph(program); Graph cfg = ProgramUtils.buildControlFlowGraph(program);
@ -274,11 +275,9 @@ public class GCShadowStackContributor {
int[] previousStates = step.slotStates; int[] previousStates = step.slotStates;
int[] states = previousStates.clone(); int[] states = previousStates.clone();
IntObjectMap<BitSet> callSites = liveInInformation.get(step.node); Map<Instruction, BitSet> callSites = liveInInformation.get(step.node);
IntObjectMap<int[]> updatesByCallSite = slotsToUpdate.get(step.node); Map<Instruction, int[]> updatesByCallSite = slotsToUpdate.get(step.node);
int[] callSiteLocations = callSites.keys().toArray(); for (Instruction callSiteLocation : sortInstructions(callSites.keySet(), program.basicBlockAt(step.node))) {
Arrays.sort(callSiteLocations);
for (int callSiteLocation : callSiteLocations) {
BitSet liveIns = callSites.get(callSiteLocation); BitSet liveIns = callSites.get(callSiteLocation);
for (int liveVar = liveIns.nextSetBit(0); liveVar >= 0; liveVar = liveIns.nextSetBit(liveVar + 1)) { for (int liveVar = liveIns.nextSetBit(0); liveVar >= 0; liveVar = liveIns.nextSetBit(liveVar + 1)) {
int slot = colors[liveVar]; int slot = colors[liveVar];
@ -305,6 +304,17 @@ public class GCShadowStackContributor {
return slotsToUpdate; return slotsToUpdate;
} }
private List<Instruction> sortInstructions(Collection<Instruction> instructions, BasicBlock block) {
ObjectIntMap<Instruction> indexes = new ObjectIntOpenHashMap<>();
int index = 0;
for (Instruction instruction : block) {
indexes.put(instruction, index++);
}
List<Instruction> sortedInstructions = new ArrayList<>(instructions);
sortedInstructions.sort(Comparator.comparing(insn -> indexes.getOrDefault(insn, -1)));
return sortedInstructions;
}
private static int[] compareStates(int[] oldStates, int[] newStates, boolean[] autoSpilled) { private static int[] compareStates(int[] oldStates, int[] newStates, boolean[] autoSpilled) {
int[] comparison = new int[oldStates.length]; int[] comparison = new int[oldStates.length];
Arrays.fill(comparison, -2); Arrays.fill(comparison, -2);
@ -324,24 +334,30 @@ public class GCShadowStackContributor {
return comparison; return comparison;
} }
private void putLiveInGCRoots(Program program, List<IntObjectMap<int[]>> updateInformation) { private void putLiveInGCRoots(Program program, List<Map<Instruction, int[]>> updateInformation) {
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
IntObjectMap<int[]> updatesByIndex = updateInformation.get(i); Map<Instruction, int[]> updatesByIndex = updateInformation.get(i);
int[] callSiteLocations = updatesByIndex.keys().toArray(); Instruction[] callSiteLocations = updatesByIndex.keySet().toArray(new Instruction[0]);
Arrays.sort(callSiteLocations); ObjectIntMap<Instruction> instructionIndexes = getInstructionIndexes(block);
for (int j = callSiteLocations.length - 1; j >= 0; --j) { Arrays.sort(callSiteLocations, Comparator.comparing(instructionIndexes::get));
int callSiteLocation = callSiteLocations[j]; for (Instruction callSiteLocation : updatesByIndex.keySet()) {
int[] updates = updatesByIndex.get(callSiteLocation); int[] updates = updatesByIndex.get(callSiteLocation);
storeLiveIns(block, callSiteLocation, updates); storeLiveIns(block, callSiteLocation, updates);
} }
} }
} }
private void storeLiveIns(BasicBlock block, int index, int[] updates) { private ObjectIntMap<Instruction> getInstructionIndexes(BasicBlock block) {
ObjectIntMap<Instruction> indexes = new ObjectIntOpenHashMap<>();
for (Instruction instruction : block) {
indexes.put(instruction, indexes.size());
}
return indexes;
}
private void storeLiveIns(BasicBlock block, Instruction callInstruction, int[] updates) {
Program program = block.getProgram(); Program program = block.getProgram();
List<Instruction> instructions = block.getInstructions();
Instruction callInstruction = instructions.get(index);
List<Instruction> instructionsToAdd = new ArrayList<>(); List<Instruction> instructionsToAdd = new ArrayList<>();
for (int slot = 0; slot < updates.length; ++slot) { for (int slot = 0; slot < updates.length; ++slot) {
@ -372,7 +388,7 @@ public class GCShadowStackContributor {
instructionsToAdd.add(registerInvocation); instructionsToAdd.add(registerInvocation);
} }
instructions.addAll(index, instructionsToAdd); callInstruction.insertPreviousAll(instructionsToAdd);
} }
private boolean isReference(TypeInferer typeInferer, int var) { private boolean isReference(TypeInferer typeInferer, int var) {

View File

@ -78,7 +78,7 @@ public class ShadowStackTransformer {
invocation.getArguments().add(sizeVariable); invocation.getArguments().add(sizeVariable);
instructionsToAdd.add(invocation); instructionsToAdd.add(invocation);
block.getInstructions().addAll(0, instructionsToAdd); block.addFirstAll(instructionsToAdd);
} }
private void addStackRelease(Program program, int maxDepth) { private void addStackRelease(Program program, int maxDepth) {
@ -101,7 +101,7 @@ public class ShadowStackTransformer {
} else { } else {
exitBlock = program.createBasicBlock(); exitBlock = program.createBasicBlock();
ExitInstruction exit = new ExitInstruction(); ExitInstruction exit = new ExitInstruction();
exitBlock.getInstructions().add(exit); exitBlock.add(exit);
if (hasResult) { if (hasResult) {
Phi phi = new Phi(); Phi phi = new Phi();
@ -125,7 +125,7 @@ public class ShadowStackTransformer {
jumpToExit.setLocation(oldExit.getLocation()); jumpToExit.setLocation(oldExit.getLocation());
jumpToExit.setLocation(oldExit.getLocation()); jumpToExit.setLocation(oldExit.getLocation());
block.getInstructions().set(block.getInstructions().size() - 1, jumpToExit); block.getLastInstruction().replace(jumpToExit);
} }
} }
@ -143,6 +143,6 @@ public class ShadowStackTransformer {
invocation.getArguments().add(sizeVariable); invocation.getArguments().add(sizeVariable);
instructionsToAdd.add(invocation); instructionsToAdd.add(invocation);
exitBlock.getInstructions().addAll(exitBlock.getInstructions().size() - 1, instructionsToAdd); exitBlock.getLastInstruction().insertPreviousAll(instructionsToAdd);
} }
} }

View File

@ -15,10 +15,10 @@
*/ */
package org.teavm.model.optimization; package org.teavm.model.optimization;
import java.util.ArrayList; import org.teavm.model.BasicBlock;
import java.util.List; import org.teavm.model.Instruction;
import org.teavm.model.*; import org.teavm.model.Program;
import org.teavm.model.instructions.EmptyInstruction; import org.teavm.model.Variable;
import org.teavm.model.instructions.UnwrapArrayInstruction; import org.teavm.model.instructions.UnwrapArrayInstruction;
import org.teavm.model.util.DefinitionExtractor; import org.teavm.model.util.DefinitionExtractor;
@ -32,42 +32,32 @@ public class ArrayUnwrapMotion implements MethodOptimization {
} }
private void optimize(BasicBlock block) { private void optimize(BasicBlock block) {
List<Instruction> newInstructions = new ArrayList<>(); for (Instruction insn : block) {
List<Instruction> instructions = block.getInstructions();
for (int i = 0; i < instructions.size(); ++i) {
Instruction insn = instructions.get(i);
if (insn instanceof UnwrapArrayInstruction) { if (insn instanceof UnwrapArrayInstruction) {
UnwrapArrayInstruction unwrap = (UnwrapArrayInstruction) insn; UnwrapArrayInstruction unwrap = (UnwrapArrayInstruction) insn;
EmptyInstruction empty = new EmptyInstruction(); Instruction def = whereDefined(insn, unwrap.getArray());
empty.setLocation(unwrap.getLocation()); insn.delete();
instructions.set(i, empty); if (def == null) {
int def = whereDefined(instructions, i, unwrap.getArray()); block.addFirst(unwrap);
if (def < 0) {
newInstructions.add(unwrap);
} else { } else {
instructions.add(def + 1, unwrap); def.insertNext(unwrap);
unwrap.setLocation(instructions.get(def).getLocation()); unwrap.setLocation(def.getLocation());
++i;
} }
} }
} }
if (!newInstructions.isEmpty()) {
instructions.addAll(0, newInstructions);
}
} }
private int whereDefined(List<Instruction> instructions, int index, Variable var) { private Instruction whereDefined(Instruction instruction, Variable var) {
DefinitionExtractor def = new DefinitionExtractor(); DefinitionExtractor def = new DefinitionExtractor();
while (index >= 0) { while (instruction != null) {
Instruction insn = instructions.get(index); instruction.acceptVisitor(def);
insn.acceptVisitor(def);
for (Variable defVar : def.getDefinedVariables()) { for (Variable defVar : def.getDefinedVariables()) {
if (defVar == var) { if (defVar == var) {
return index; return instruction;
} }
} }
--index; instruction = instruction.getPrevious();
} }
return index; return instruction;
} }
} }

View File

@ -18,7 +18,6 @@ package org.teavm.model.optimization;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Deque; import java.util.Deque;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import org.teavm.common.DominatorTree; import org.teavm.common.DominatorTree;
import org.teavm.common.Graph; import org.teavm.common.Graph;
@ -26,7 +25,6 @@ import org.teavm.common.GraphUtils;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
import org.teavm.model.Instruction; import org.teavm.model.Instruction;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.instructions.EmptyInstruction;
import org.teavm.model.instructions.InitClassInstruction; import org.teavm.model.instructions.InitClassInstruction;
import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.util.ProgramUtils; import org.teavm.model.util.ProgramUtils;
@ -47,16 +45,14 @@ public class ClassInitElimination implements MethodOptimization {
Step step = stack.pop(); Step step = stack.pop();
int node = step.node; int node = step.node;
BasicBlock block = program.basicBlockAt(node); BasicBlock block = program.basicBlockAt(node);
List<Instruction> instructions = block.getInstructions();
for (int i = 0; i < instructions.size(); ++i) { Instruction nextInsn;
Instruction insn = instructions.get(i); for (Instruction insn = block.getFirstInstruction(); insn != null; insn = nextInsn) {
nextInsn = insn.getNext();
if (insn instanceof InitClassInstruction) { if (insn instanceof InitClassInstruction) {
InitClassInstruction initClass = (InitClassInstruction) insn; InitClassInstruction initClass = (InitClassInstruction) insn;
if (!step.initializedClasses.add(initClass.getClassName())) { if (!step.initializedClasses.add(initClass.getClassName())) {
EmptyInstruction empty = new EmptyInstruction(); insn.delete();
empty.setLocation(initClass.getLocation());
instructions.set(i, empty);
} }
continue; continue;
} }

View File

@ -38,7 +38,7 @@ public class ConstantConditionElimination implements MethodOptimization {
nullConstants = new boolean[program.variableCount()]; nullConstants = new boolean[program.variableCount()];
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) { for (Instruction insn : block) {
if (insn instanceof IntegerConstantInstruction) { if (insn instanceof IntegerConstantInstruction) {
IntegerConstantInstruction constInsn = (IntegerConstantInstruction) insn; IntegerConstantInstruction constInsn = (IntegerConstantInstruction) insn;
int receiver = constInsn.getReceiver().getIndex(); int receiver = constInsn.getReceiver().getIndex();
@ -61,7 +61,7 @@ public class ConstantConditionElimination implements MethodOptimization {
JumpInstruction jump = new JumpInstruction(); JumpInstruction jump = new JumpInstruction();
jump.setTarget(target); jump.setTarget(target);
jump.setLocation(insn.getLocation()); jump.setLocation(insn.getLocation());
block.getInstructions().set(block.getInstructions().size() - 1, jump); block.getLastInstruction().replace(jump);
changed = true; changed = true;
} }
} }

View File

@ -24,10 +24,6 @@ import org.teavm.model.*;
import org.teavm.model.instructions.InvocationType; import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.InvokeInstruction;
/**
*
* @author Alexey Andreev
*/
public class Devirtualization { public class Devirtualization {
private DependencyInfo dependency; private DependencyInfo dependency;
private ClassReaderSource classSource; private ClassReaderSource classSource;
@ -45,7 +41,7 @@ public class Devirtualization {
Program program = method.getProgram(); Program program = method.getProgram();
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) { for (Instruction insn : block) {
if (!(insn instanceof InvokeInstruction)) { if (!(insn instanceof InvokeInstruction)) {
continue; continue;
} }

View File

@ -31,7 +31,7 @@ public class EmptyBlockElimination implements MethodOptimization {
int lastNonEmpty = program.basicBlockCount() - 1; int lastNonEmpty = program.basicBlockCount() - 1;
for (int i = program.basicBlockCount() - 2; i > 0; --i) { for (int i = program.basicBlockCount() - 2; i > 0; --i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
if (block.getPhis().isEmpty() && block.getInstructions().size() == 1 if (block.getPhis().isEmpty() && block.instructionCount() == 1
&& block.getLastInstruction() instanceof JumpInstruction) { && block.getLastInstruction() instanceof JumpInstruction) {
JumpInstruction insn = (JumpInstruction) block.getLastInstruction(); JumpInstruction insn = (JumpInstruction) block.getLastInstruction();
if (insn.getTarget().getIndex() == i + 1) { if (insn.getTarget().getIndex() == i + 1) {
@ -40,7 +40,7 @@ public class EmptyBlockElimination implements MethodOptimization {
} }
lastNonEmpty = blockMapping[i]; lastNonEmpty = blockMapping[i];
} }
new BasicBlockMapper(block -> blockMapping[block]).transform(program); new BasicBlockMapper((int block) -> blockMapping[block]).transform(program);
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
if (blockMapping[i] != i) { if (blockMapping[i] != i) {
program.deleteBasicBlock(i); program.deleteBasicBlock(i);

View File

@ -81,15 +81,14 @@ public class GlobalValueNumbering implements MethodOptimization {
block.setExceptionVariable(program.variableAt(var)); block.setExceptionVariable(program.variableAt(var));
} }
for (int i = 0; i < block.getInstructions().size(); ++i) { for (Instruction currentInsn : block) {
evaluatedConstant = null; evaluatedConstant = null;
Instruction currentInsn = block.getInstructions().get(i);
currentInsn.acceptVisitor(optimizer); currentInsn.acceptVisitor(optimizer);
if (eliminate) { if (eliminate) {
affected = true; affected = true;
EmptyInstruction empty = new EmptyInstruction(); EmptyInstruction empty = new EmptyInstruction();
empty.setLocation(currentInsn.getLocation()); empty.setLocation(currentInsn.getLocation());
block.getInstructions().set(i, empty); currentInsn.replace(empty);
eliminate = false; eliminate = false;
} else if (evaluatedConstant != null) { } else if (evaluatedConstant != null) {
if (evaluatedConstant instanceof Integer) { if (evaluatedConstant instanceof Integer) {
@ -97,25 +96,25 @@ public class GlobalValueNumbering implements MethodOptimization {
newInsn.setConstant((Integer) evaluatedConstant); newInsn.setConstant((Integer) evaluatedConstant);
newInsn.setReceiver(program.variableAt(receiver)); newInsn.setReceiver(program.variableAt(receiver));
newInsn.setLocation(currentInsn.getLocation()); newInsn.setLocation(currentInsn.getLocation());
block.getInstructions().set(i, newInsn); currentInsn.replace(newInsn);
} else if (evaluatedConstant instanceof Long) { } else if (evaluatedConstant instanceof Long) {
LongConstantInstruction newInsn = new LongConstantInstruction(); LongConstantInstruction newInsn = new LongConstantInstruction();
newInsn.setConstant((Long) evaluatedConstant); newInsn.setConstant((Long) evaluatedConstant);
newInsn.setReceiver(program.variableAt(receiver)); newInsn.setReceiver(program.variableAt(receiver));
newInsn.setLocation(currentInsn.getLocation()); newInsn.setLocation(currentInsn.getLocation());
block.getInstructions().set(i, newInsn); currentInsn.replace(newInsn);
} else if (evaluatedConstant instanceof Float) { } else if (evaluatedConstant instanceof Float) {
FloatConstantInstruction newInsn = new FloatConstantInstruction(); FloatConstantInstruction newInsn = new FloatConstantInstruction();
newInsn.setConstant((Float) evaluatedConstant); newInsn.setConstant((Float) evaluatedConstant);
newInsn.setReceiver(program.variableAt(receiver)); newInsn.setReceiver(program.variableAt(receiver));
newInsn.setLocation(currentInsn.getLocation()); newInsn.setLocation(currentInsn.getLocation());
block.getInstructions().set(i, newInsn); currentInsn.replace(newInsn);
} else if (evaluatedConstant instanceof Double) { } else if (evaluatedConstant instanceof Double) {
DoubleConstantInstruction newInsn = new DoubleConstantInstruction(); DoubleConstantInstruction newInsn = new DoubleConstantInstruction();
newInsn.setConstant((Double) evaluatedConstant); newInsn.setConstant((Double) evaluatedConstant);
newInsn.setReceiver(program.variableAt(receiver)); newInsn.setReceiver(program.variableAt(receiver));
newInsn.setLocation(currentInsn.getLocation()); newInsn.setLocation(currentInsn.getLocation());
block.getInstructions().set(i, newInsn); currentInsn.replace(newInsn);
} }
} }
} }

View File

@ -29,6 +29,7 @@ import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.Phi; import org.teavm.model.Phi;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.TryCatchBlock;
import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.BinaryBranchingInstruction; import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BranchingInstruction; import org.teavm.model.instructions.BranchingInstruction;
@ -62,7 +63,7 @@ public class Inlining {
private void execPlanEntry(Program program, PlanEntry planEntry, int offset) { private void execPlanEntry(Program program, PlanEntry planEntry, int offset) {
BasicBlock block = program.basicBlockAt(planEntry.targetBlock + offset); BasicBlock block = program.basicBlockAt(planEntry.targetBlock + offset);
InvokeInstruction invoke = (InvokeInstruction) block.getInstructions().get(planEntry.targetInstruction); InvokeInstruction invoke = (InvokeInstruction) planEntry.targetInstruction;
BasicBlock splitBlock = program.createBasicBlock(); BasicBlock splitBlock = program.createBasicBlock();
BasicBlock firstInlineBlock = program.createBasicBlock(); BasicBlock firstInlineBlock = program.createBasicBlock();
Program inlineProgram = planEntry.program; Program inlineProgram = planEntry.program;
@ -75,30 +76,43 @@ public class Inlining {
program.createVariable(); program.createVariable();
} }
List<Instruction> movedInstructions = block.getInstructions().subList(planEntry.targetInstruction + 1, while (planEntry.targetInstruction.getNext() != null) {
block.getInstructions().size()); Instruction insn = planEntry.targetInstruction.getNext();
List<Instruction> instructionsToMove = new ArrayList<>(movedInstructions); insn.delete();
movedInstructions.clear(); splitBlock.add(insn);
splitBlock.getInstructions().addAll(instructionsToMove); }
splitBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program)); splitBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
block.getInstructions().remove(block.getInstructions().size() - 1); invoke.delete();
if (invoke.getInstance() == null || invoke.getMethod().getName().equals("<init>")) { if (invoke.getInstance() == null || invoke.getMethod().getName().equals("<init>")) {
InitClassInstruction clinit = new InitClassInstruction(); InitClassInstruction clinit = new InitClassInstruction();
clinit.setClassName(invoke.getMethod().getClassName()); clinit.setClassName(invoke.getMethod().getClassName());
block.getInstructions().add(clinit); block.add(clinit);
} }
JumpInstruction jumpToInlinedProgram = new JumpInstruction(); JumpInstruction jumpToInlinedProgram = new JumpInstruction();
jumpToInlinedProgram.setTarget(firstInlineBlock); jumpToInlinedProgram.setTarget(firstInlineBlock);
block.getInstructions().add(jumpToInlinedProgram); block.add(jumpToInlinedProgram);
for (int i = 0; i < inlineProgram.basicBlockCount(); ++i) { for (int i = 0; i < inlineProgram.basicBlockCount(); ++i) {
BasicBlock blockToInline = inlineProgram.basicBlockAt(i); BasicBlock blockToInline = inlineProgram.basicBlockAt(i);
BasicBlock inlineBlock = program.basicBlockAt(firstInlineBlock.getIndex() + i); BasicBlock inlineBlock = program.basicBlockAt(firstInlineBlock.getIndex() + i);
ProgramUtils.copyBasicBlock(blockToInline, inlineBlock); while (blockToInline.getFirstInstruction() != null) {
Instruction insn = blockToInline.getFirstInstruction();
insn.delete();
inlineBlock.add(insn);
} }
BasicBlockMapper blockMapper = new BasicBlockMapper(index -> index + firstInlineBlock.getIndex()); List<Phi> phis = new ArrayList<>(blockToInline.getPhis());
blockToInline.getPhis().clear();
inlineBlock.getPhis().addAll(phis);
List<TryCatchBlock> tryCatches = new ArrayList<>(blockToInline.getTryCatchBlocks());
blockToInline.getTryCatchBlocks().clear();
inlineBlock.getTryCatchBlocks().addAll(tryCatches);
}
BasicBlockMapper blockMapper = new BasicBlockMapper((BasicBlock b) ->
program.basicBlockAt(b.getIndex() + firstInlineBlock.getIndex()));
InstructionVariableMapper variableMapper = new InstructionVariableMapper(var -> { InstructionVariableMapper variableMapper = new InstructionVariableMapper(var -> {
if (var.getIndex() == 0) { if (var.getIndex() == 0) {
return invoke.getInstance(); return invoke.getInstance();
@ -120,7 +134,7 @@ public class Inlining {
ExitInstruction exit = (ExitInstruction) lastInsn; ExitInstruction exit = (ExitInstruction) lastInsn;
JumpInstruction exitReplacement = new JumpInstruction(); JumpInstruction exitReplacement = new JumpInstruction();
exitReplacement.setTarget(splitBlock); exitReplacement.setTarget(splitBlock);
mappedBlock.getInstructions().set(mappedBlock.getInstructions().size() - 1, exitReplacement); exit.replace(exitReplacement);
if (exit.getValueToReturn() != null) { if (exit.getValueToReturn() != null) {
Incoming resultIncoming = new Incoming(); Incoming resultIncoming = new Incoming();
resultIncoming.setSource(mappedBlock); resultIncoming.setSource(mappedBlock);
@ -135,7 +149,7 @@ public class Inlining {
AssignInstruction resultAssignment = new AssignInstruction(); AssignInstruction resultAssignment = new AssignInstruction();
resultAssignment.setReceiver(invoke.getReceiver()); resultAssignment.setReceiver(invoke.getReceiver());
resultAssignment.setAssignee(resultVariables.get(0).getValue()); resultAssignment.setAssignee(resultVariables.get(0).getValue());
splitBlock.getInstructions().add(0, resultAssignment); splitBlock.addFirst(resultAssignment);
} else { } else {
Phi resultPhi = new Phi(); Phi resultPhi = new Phi();
resultPhi.setReceiver(invoke.getReceiver()); resultPhi.setReceiver(invoke.getReceiver());
@ -170,14 +184,11 @@ public class Inlining {
List<PlanEntry> plan = new ArrayList<>(); List<PlanEntry> plan = new ArrayList<>();
int ownComplexity = getComplexity(program); int ownComplexity = getComplexity(program);
for (int i = program.basicBlockCount() - 1; i >= 0; --i) { for (BasicBlock block : program.getBasicBlocks()) {
BasicBlock block = program.basicBlockAt(i);
if (!block.getTryCatchBlocks().isEmpty()) { if (!block.getTryCatchBlocks().isEmpty()) {
continue; continue;
} }
List<Instruction> instructions = block.getInstructions(); for (Instruction insn : block) {
for (int j = instructions.size() - 1; j >= 0; --j) {
Instruction insn = instructions.get(j);
if (!(insn instanceof InvokeInstruction)) { if (!(insn instanceof InvokeInstruction)) {
continue; continue;
} }
@ -202,13 +213,14 @@ public class Inlining {
} }
PlanEntry entry = new PlanEntry(); PlanEntry entry = new PlanEntry();
entry.targetBlock = i; entry.targetBlock = block.getIndex();
entry.targetInstruction = j; entry.targetInstruction = insn;
entry.program = invokedProgram; entry.program = invokedProgram;
entry.innerPlan.addAll(buildPlan(invokedProgram, classSource, depth + 1)); entry.innerPlan.addAll(buildPlan(invokedProgram, classSource, depth + 1));
plan.add(entry); plan.add(entry);
} }
} }
Collections.reverse(plan);
return plan; return plan;
} }
@ -222,20 +234,20 @@ public class Inlining {
int complexity = 0; int complexity = 0;
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
List<Instruction> instructions = block.getInstructions(); int nopCount = 0;
int nopCount = (int) instructions.stream().filter(insn -> insn instanceof EmptyInstruction).count(); int invokeCount = 0;
int invokeCount = instructions.stream().mapToInt(insn -> { for (Instruction insn : block) {
if (!(insn instanceof InvokeInstruction)) { if (insn instanceof EmptyInstruction) {
return 0; nopCount++;
} } else if (insn instanceof InvokeInstruction) {
InvokeInstruction invoke = (InvokeInstruction) insn; InvokeInstruction invoke = (InvokeInstruction) insn;
int count = invoke.getArguments().size(); invokeCount += invoke.getArguments().size();
if (invoke.getInstance() != null) { if (invoke.getInstance() != null) {
count++; invokeCount++;
} }
return count + 1; }
}).sum(); }
complexity += instructions.size() - 1 - nopCount + invokeCount; complexity += block.instructionCount() - nopCount + invokeCount;
Instruction lastInsn = block.getLastInstruction(); Instruction lastInsn = block.getLastInstruction();
if (lastInsn instanceof SwitchInstruction) { if (lastInsn instanceof SwitchInstruction) {
complexity += 3; complexity += 3;
@ -248,7 +260,7 @@ public class Inlining {
private class PlanEntry { private class PlanEntry {
int targetBlock; int targetBlock;
int targetInstruction; Instruction targetInstruction;
Program program; Program program;
final List<PlanEntry> innerPlan = new ArrayList<>(); final List<PlanEntry> innerPlan = new ArrayList<>();
} }

View File

@ -65,8 +65,9 @@ public class LoopInvariantMotion implements MethodOptimization {
boolean dominatesExits = exits != null && Arrays.stream(exits) boolean dominatesExits = exits != null && Arrays.stream(exits)
.allMatch(exit -> dom.dominates(v, exit)); .allMatch(exit -> dom.dominates(v, exit));
BasicBlock block = program.basicBlockAt(v); BasicBlock block = program.basicBlockAt(v);
insnLoop: for (int i = 0; i < block.getInstructions().size(); ++i) { Instruction nextInsn;
Instruction insn = block.getInstructions().get(i); insnLoop: for (Instruction insn = block.getFirstInstruction(); insn != null; insn = nextInsn) {
nextInsn = insn.getNext();
insn.acceptVisitor(defExtractor); insn.acceptVisitor(defExtractor);
Variable[] defs = defExtractor.getDefinedVariables(); Variable[] defs = defExtractor.getDefinedVariables();
for (Variable def : defs) { for (Variable def : defs) {
@ -113,9 +114,8 @@ public class LoopInvariantMotion implements MethodOptimization {
EmptyInstruction empty = new EmptyInstruction(); EmptyInstruction empty = new EmptyInstruction();
empty.setLocation(insn.getLocation()); empty.setLocation(insn.getLocation());
block.getInstructions().set(i, empty); insn.replace(empty);
int preheader = getPreheader(defLoop.getHead()); BasicBlock preheader = program.basicBlockAt(getPreheader(defLoop.getHead()));
List<Instruction> preheaderInstructions = program.basicBlockAt(preheader).getInstructions();
List<Instruction> newInstructions = new ArrayList<>(); List<Instruction> newInstructions = new ArrayList<>();
Variable[] variableMap = null; Variable[] variableMap = null;
for (Variable use : useExtractor.getUsedVariables()) { for (Variable use : useExtractor.getUsedVariables()) {
@ -137,7 +137,7 @@ public class LoopInvariantMotion implements MethodOptimization {
insn.acceptVisitor(new InstructionVariableMapper(var -> currentVariableMap[var.getIndex()])); insn.acceptVisitor(new InstructionVariableMapper(var -> currentVariableMap[var.getIndex()]));
} }
newInstructions.add(insn); newInstructions.add(insn);
preheaderInstructions.addAll(preheaderInstructions.size() - 1, newInstructions); preheader.getLastInstruction().insertPreviousAll(newInstructions);
defLocation[defs[0].getIndex()] = commonUseLoop != null ? commonUseLoop.getHead() : 0; defLocation[defs[0].getIndex()] = commonUseLoop != null ? commonUseLoop.getHead() : 0;
affected = true; affected = true;
} }
@ -180,7 +180,7 @@ public class LoopInvariantMotion implements MethodOptimization {
JumpInstruction escapeInsn = new JumpInstruction(); JumpInstruction escapeInsn = new JumpInstruction();
BasicBlock header = program.basicBlockAt(headerIndex); BasicBlock header = program.basicBlockAt(headerIndex);
escapeInsn.setTarget(header); escapeInsn.setTarget(header);
preheader.getInstructions().add(escapeInsn); preheader.add(escapeInsn);
for (Phi phi : header.getPhis()) { for (Phi phi : header.getPhis()) {
Phi preheaderPhi = null; Phi preheaderPhi = null;
@ -208,7 +208,7 @@ public class LoopInvariantMotion implements MethodOptimization {
if (!dom.dominates(headerIndex, predIndex)) { if (!dom.dominates(headerIndex, predIndex)) {
BasicBlock pred = program.basicBlockAt(predIndex); BasicBlock pred = program.basicBlockAt(predIndex);
pred.getLastInstruction().acceptVisitor(new BasicBlockMapper( pred.getLastInstruction().acceptVisitor(new BasicBlockMapper(
block -> block == header.getIndex() ? preheader.getIndex() : block)); (int block) -> block == header.getIndex() ? preheader.getIndex() : block));
} }
} }

View File

@ -227,7 +227,7 @@ class LoopInversionImpl {
} }
BasicBlock block = program.basicBlockAt(node); BasicBlock block = program.basicBlockAt(node);
Set<Variable> currentInvariants = new HashSet<>(); Set<Variable> currentInvariants = new HashSet<>();
for (Instruction insn : block.getInstructions()) { for (Instruction insn : block) {
invariantAnalyzer.reset(); invariantAnalyzer.reset();
insn.acceptVisitor(invariantAnalyzer); insn.acceptVisitor(invariantAnalyzer);
if (!invariantAnalyzer.canMove && !invariantAnalyzer.constant) { if (!invariantAnalyzer.canMove && !invariantAnalyzer.constant) {
@ -304,7 +304,7 @@ class LoopInversionImpl {
} }
private void copyCondition() { private void copyCondition() {
BasicBlockMapper blockMapper = new BasicBlockMapper(block -> copiedNodes.getOrDefault(block, block)); BasicBlockMapper blockMapper = new BasicBlockMapper((int block) -> copiedNodes.getOrDefault(block, block));
InstructionCopyReader copier = new InstructionCopyReader(program); InstructionCopyReader copier = new InstructionCopyReader(program);
for (int node : copiedNodes.keys().toArray()) { for (int node : copiedNodes.keys().toArray()) {
@ -314,11 +314,11 @@ class LoopInversionImpl {
targetBlock.setExceptionVariable(sourceBlock.getExceptionVariable()); targetBlock.setExceptionVariable(sourceBlock.getExceptionVariable());
copier.resetLocation(); copier.resetLocation();
for (int i = 0; i < sourceBlock.instructionCount(); ++i) { List<Instruction> instructionCopies = ProgramUtils.copyInstructions(sourceBlock.getFirstInstruction(),
sourceBlock.readInstruction(i, copier); null, targetBlock.getProgram());
Instruction insn = copier.getCopy(); for (Instruction insn : instructionCopies) {
insn.acceptVisitor(blockMapper); insn.acceptVisitor(blockMapper);
targetBlock.getInstructions().add(insn); targetBlock.add(insn);
} }
for (Phi phi : sourceBlock.getPhis()) { for (Phi phi : sourceBlock.getPhis()) {
@ -373,7 +373,7 @@ class LoopInversionImpl {
* Back edges from body are not back edges anymore, instead they point to a copied condition. * Back edges from body are not back edges anymore, instead they point to a copied condition.
*/ */
private void moveBackEdges() { private void moveBackEdges() {
BasicBlockMapper mapper = new BasicBlockMapper(block -> block == head ? headCopy : block); BasicBlockMapper mapper = new BasicBlockMapper((int block) -> block == head ? headCopy : block);
for (int node : nodes.toArray()) { for (int node : nodes.toArray()) {
BasicBlock block = program.basicBlockAt(node); BasicBlock block = program.basicBlockAt(node);

View File

@ -15,9 +15,7 @@
*/ */
package org.teavm.model.optimization; package org.teavm.model.optimization;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import org.teavm.common.Graph; import org.teavm.common.Graph;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
import org.teavm.model.Incoming; import org.teavm.model.Incoming;
@ -58,7 +56,7 @@ public class RedundantJumpElimination implements MethodOptimization {
continue; continue;
} }
block.getInstructions().remove(block.getInstructions().size() - 1); block.getLastInstruction().delete();
for (Phi phi : target.getPhis()) { for (Phi phi : target.getPhis()) {
if (phi.getIncomings().isEmpty()) { if (phi.getIncomings().isEmpty()) {
continue; continue;
@ -67,11 +65,13 @@ public class RedundantJumpElimination implements MethodOptimization {
AssignInstruction assign = new AssignInstruction(); AssignInstruction assign = new AssignInstruction();
assign.setReceiver(phi.getReceiver()); assign.setReceiver(phi.getReceiver());
assign.setAssignee(incoming.getValue()); assign.setAssignee(incoming.getValue());
block.getInstructions().add(assign); block.add(assign);
}
while (target.getFirstInstruction() != null) {
Instruction instruction = target.getFirstInstruction();
instruction.delete();
block.add(instruction);
} }
List<Instruction> instructionsToTransfer = new ArrayList<>(target.getInstructions());
target.getInstructions().clear();
block.getInstructions().addAll(instructionsToTransfer);
Instruction lastInsn = block.getLastInstruction(); Instruction lastInsn = block.getLastInstruction();
if (lastInsn != null) { if (lastInsn != null) {

View File

@ -65,11 +65,11 @@ public class UnusedVariableElimination implements MethodOptimization {
block.setExceptionVariable(null); block.setExceptionVariable(null);
} }
for (int j = 0; j < block.getInstructions().size(); ++j) { for (Instruction insn : block) {
insnOptimizer.eliminate = false; insnOptimizer.eliminate = false;
block.getInstructions().get(j).acceptVisitor(insnOptimizer); insn.acceptVisitor(insnOptimizer);
if (insnOptimizer.eliminate) { if (insnOptimizer.eliminate) {
block.getInstructions().remove(j--); insn.delete();
} }
} }

View File

@ -18,10 +18,6 @@ package org.teavm.model.optimization;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.model.instructions.*; import org.teavm.model.instructions.*;
/**
*
* @author Alexey Andreev
*/
public final class VariableEscapeAnalyzer { public final class VariableEscapeAnalyzer {
private VariableEscapeAnalyzer() { private VariableEscapeAnalyzer() {
} }
@ -31,7 +27,7 @@ public final class VariableEscapeAnalyzer {
InstructionAnalyzer analyzer = new InstructionAnalyzer(escaping); InstructionAnalyzer analyzer = new InstructionAnalyzer(escaping);
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) { for (Instruction insn : block) {
insn.acceptVisitor(analyzer); insn.acceptVisitor(analyzer);
} }
} }

View File

@ -29,7 +29,7 @@ public final class VariableUsageGraphBuilder {
InstructionAnalyzer analyzer = new InstructionAnalyzer(builder); InstructionAnalyzer analyzer = new InstructionAnalyzer(builder);
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) { for (Instruction insn : block) {
insn.acceptVisitor(analyzer); insn.acceptVisitor(analyzer);
} }
for (Phi phi : block.getPhis()) { for (Phi phi : block.getPhis()) {

View File

@ -337,7 +337,6 @@ class InstructionStringifier implements InstructionReader {
public void getField(VariableReader receiver, VariableReader instance, FieldReference field, ValueType fieldType) { public void getField(VariableReader receiver, VariableReader instance, FieldReference field, ValueType fieldType) {
sb.append("@").append(receiver.getIndex()).append(" := field "); sb.append("@").append(receiver.getIndex()).append(" := field ");
escapeIdentifierIfNeeded(field.toString(), sb); escapeIdentifierIfNeeded(field.toString(), sb);
sb.append(field);
if (instance != null) { if (instance != null) {
sb.append(" @").append(instance.getIndex()); sb.append(" @").append(instance.getIndex());
} }
@ -407,13 +406,15 @@ class InstructionStringifier implements InstructionReader {
escapeIdentifierIfNeeded(method.toString(), sb); escapeIdentifierIfNeeded(method.toString(), sb);
if (instance != null) { if (instance != null) {
sb.append(' ');
sb.append("@").append(instance.getIndex()); sb.append("@").append(instance.getIndex());
} }
for (int i = 0; i < arguments.size(); ++i) { for (int i = 0; i < arguments.size(); ++i) {
if (instance != null || i > 0) { if (instance != null || i > 0) {
sb.append(", "); sb.append(",");
} }
sb.append(' ');
sb.append("@").append(arguments.get(i).getIndex()); sb.append("@").append(arguments.get(i).getIndex());
} }
} }

View File

@ -60,9 +60,10 @@ public class ListingBuilder {
} }
TextLocation location = null; TextLocation location = null;
for (int j = 0; j < block.instructionCount(); ++j) { for (InstructionIterator iterator = block.iterateInstructions(); iterator.hasNext();) {
iterator.next();
insnSb.setLength(0); insnSb.setLength(0);
block.readInstruction(j, stringifier); iterator.read(stringifier);
if (!Objects.equals(location, stringifier.getLocation())) { if (!Objects.equals(location, stringifier.getLocation())) {
location = stringifier.getLocation(); location = stringifier.getLocation();
sb.append(prefix).append(" at "); sb.append(prefix).append(" at ");

View File

@ -417,7 +417,7 @@ public class ListingParser {
} }
case "exception": { case "exception": {
lexer.nextToken(); lexer.nextToken();
if (!currentBlock.getInstructions().isEmpty() || currentBlock.getExceptionVariable() != null) { if (currentBlock.instructionCount() > 0 || currentBlock.getExceptionVariable() != null) {
throw new ListingParseException("Exception can be read as a first instruction", throw new ListingParseException("Exception can be read as a first instruction",
lexer.getTokenStart()); lexer.getTokenStart());
} }
@ -578,7 +578,7 @@ public class ListingParser {
lexer.nextToken(); lexer.nextToken();
} }
if (!currentBlock.getInstructions().isEmpty() || currentBlock.getExceptionVariable() != null) { if (currentBlock.instructionCount() > 0 || currentBlock.getExceptionVariable() != null) {
throw new ListingParseException("Phi must be first instruction in block", phiStart); throw new ListingParseException("Phi must be first instruction in block", phiStart);
} }
@ -1164,6 +1164,6 @@ public class ListingParser {
private void addInstruction(Instruction instruction) throws ListingParseException { private void addInstruction(Instruction instruction) throws ListingParseException {
currentTryCatch = null; currentTryCatch = null;
instruction.setLocation(currentLocation); instruction.setLocation(currentLocation);
currentBlock.getInstructions().add(instruction); currentBlock.add(instruction);
} }
} }

View File

@ -46,7 +46,7 @@ import org.teavm.model.instructions.MonitorEnterInstruction;
public class AsyncProgramSplitter { public class AsyncProgramSplitter {
private List<Part> parts = new ArrayList<>(); private List<Part> parts = new ArrayList<>();
private Map<Long, Integer> partMap = new HashMap<>(); private Map<Instruction, Integer> partMap = new HashMap<>();
private ClassReaderSource classSource; private ClassReaderSource classSource;
private Set<MethodReference> asyncMethods = new HashSet<>(); private Set<MethodReference> asyncMethods = new HashSet<>();
private Program program; private Program program;
@ -63,7 +63,7 @@ public class AsyncProgramSplitter {
Part initialPart = new Part(program.basicBlockCount()); Part initialPart = new Part(program.basicBlockCount());
initialPart.program = initialProgram; initialPart.program = initialProgram;
parts.add(initialPart); parts.add(initialPart);
partMap.put(0L, 0); partMap.put(program.basicBlockAt(0).getFirstInstruction(), 0);
Step initialStep = new Step(); Step initialStep = new Step();
initialStep.source = 0; initialStep.source = 0;
initialStep.targetPart = initialPart; initialStep.targetPart = initialPart;
@ -78,9 +78,8 @@ public class AsyncProgramSplitter {
} }
BasicBlock sourceBlock = program.basicBlockAt(step.source); BasicBlock sourceBlock = program.basicBlockAt(step.source);
step.targetPart.originalBlocks[step.source] = step.source; step.targetPart.originalBlocks[step.source] = step.source;
int last = 0; Instruction last = sourceBlock.getFirstInstruction();
for (int i = 0; i < sourceBlock.getInstructions().size(); ++i) { for (Instruction insn : sourceBlock) {
Instruction insn = sourceBlock.getInstructions().get(i);
if (insn instanceof InvokeInstruction) { if (insn instanceof InvokeInstruction) {
InvokeInstruction invoke = (InvokeInstruction) insn; InvokeInstruction invoke = (InvokeInstruction) insn;
if (!asyncMethods.contains(findRealMethod(invoke.getMethod()))) { if (!asyncMethods.contains(findRealMethod(invoke.getMethod()))) {
@ -96,8 +95,7 @@ public class AsyncProgramSplitter {
// If we met asynchronous invocation... // If we met asynchronous invocation...
// Copy portion of current block from last occurrence (or from start) to i'th instruction. // Copy portion of current block from last occurrence (or from start) to i'th instruction.
targetBlock.getInstructions().addAll(ProgramUtils.copyInstructions(sourceBlock, targetBlock.addAll(ProgramUtils.copyInstructions(last, insn, targetBlock.getProgram()));
last, i, targetBlock.getProgram()));
targetBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(sourceBlock, targetBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(sourceBlock,
targetBlock.getProgram())); targetBlock.getProgram()));
for (TryCatchBlock tryCatch : targetBlock.getTryCatchBlocks()) { for (TryCatchBlock tryCatch : targetBlock.getTryCatchBlocks()) {
@ -108,15 +106,14 @@ public class AsyncProgramSplitter {
queue.add(next); queue.add(next);
} }
} }
last = i; last = insn;
step.targetPart.splitPoints[targetBlock.getIndex()] = i; step.targetPart.splitPoints[targetBlock.getIndex()] = insn;
// If this instruction already separates program, end with current block and refer to the // If this instruction already separates program, end with current block and refer to the
// existing part // existing part
long key = ((long) step.source << 32) | i; if (partMap.containsKey(insn)) {
if (partMap.containsKey(key)) { step.targetPart.blockSuccessors[targetBlock.getIndex()] = partMap.get(insn);
step.targetPart.blockSuccessors[targetBlock.getIndex()] = partMap.get(key);
continue taskLoop; continue taskLoop;
} }
@ -128,7 +125,7 @@ public class AsyncProgramSplitter {
parts.add(part); parts.add(part);
// Mark current instruction as a separator and remember which part is in charge. // Mark current instruction as a separator and remember which part is in charge.
partMap.put(key, partId); partMap.put(insn, partId);
step.targetPart.blockSuccessors[targetBlock.getIndex()] = partId; step.targetPart.blockSuccessors[targetBlock.getIndex()] = partId;
// Continue with a new block in the new part // Continue with a new block in the new part
@ -136,15 +133,14 @@ public class AsyncProgramSplitter {
if (step.source > 0) { if (step.source > 0) {
JumpInstruction jumpToNextBlock = new JumpInstruction(); JumpInstruction jumpToNextBlock = new JumpInstruction();
jumpToNextBlock.setTarget(targetBlock); jumpToNextBlock.setTarget(targetBlock);
nextProgram.basicBlockAt(0).getInstructions().add(jumpToNextBlock); nextProgram.basicBlockAt(0).add(jumpToNextBlock);
nextProgram.basicBlockAt(0).getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(sourceBlock, nextProgram.basicBlockAt(0).getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(sourceBlock,
nextProgram)); nextProgram));
} }
step.targetPart = part; step.targetPart = part;
part.originalBlocks[targetBlock.getIndex()] = step.source; part.originalBlocks[targetBlock.getIndex()] = step.source;
} }
targetBlock.getInstructions().addAll(ProgramUtils.copyInstructions(sourceBlock, targetBlock.addAll(ProgramUtils.copyInstructions(last, null, targetBlock.getProgram()));
last, sourceBlock.getInstructions().size(), targetBlock.getProgram()));
targetBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(sourceBlock, targetBlock.getProgram())); targetBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(sourceBlock, targetBlock.getProgram()));
for (TryCatchBlock tryCatch : targetBlock.getTryCatchBlocks()) { for (TryCatchBlock tryCatch : targetBlock.getTryCatchBlocks()) {
if (tryCatch.getHandler() != null) { if (tryCatch.getHandler() != null) {
@ -170,18 +166,18 @@ public class AsyncProgramSplitter {
for (Part part : parts) { for (Part part : parts) {
IntegerArray blockSuccessors = IntegerArray.of(part.blockSuccessors); IntegerArray blockSuccessors = IntegerArray.of(part.blockSuccessors);
IntegerArray originalBlocks = IntegerArray.of(part.originalBlocks); IntegerArray originalBlocks = IntegerArray.of(part.originalBlocks);
IntegerArray splitPoints = IntegerArray.of(part.splitPoints); List<Instruction> splitPoints = new ArrayList<>(Arrays.asList(part.splitPoints));
AsyncProgramSplittingBackend splittingBackend = new AsyncProgramSplittingBackend( AsyncProgramSplittingBackend splittingBackend = new AsyncProgramSplittingBackend(
new ProgramNodeSplittingBackend(part.program), blockSuccessors, originalBlocks, splitPoints); new ProgramNodeSplittingBackend(part.program), blockSuccessors, originalBlocks, splitPoints);
Graph graph = ProgramUtils.buildControlFlowGraph(part.program); Graph graph = ProgramUtils.buildControlFlowGraph(part.program);
int[] weights = new int[graph.size()]; int[] weights = new int[graph.size()];
for (int i = 0; i < part.program.basicBlockCount(); ++i) { for (int i = 0; i < part.program.basicBlockCount(); ++i) {
weights[i] = part.program.basicBlockAt(i).getInstructions().size(); weights[i] = part.program.basicBlockAt(i).instructionCount();
} }
GraphUtils.splitIrreducibleGraph(graph, weights, splittingBackend); GraphUtils.splitIrreducibleGraph(graph, weights, splittingBackend);
part.blockSuccessors = splittingBackend.blockSuccessors.getAll(); part.blockSuccessors = splittingBackend.blockSuccessors.getAll();
part.originalBlocks = splittingBackend.originalBlocks.getAll(); part.originalBlocks = splittingBackend.originalBlocks.getAll();
part.splitPoints = splittingBackend.splitPoints.getAll(); part.splitPoints = splittingBackend.splitPoints.toArray(new Instruction[0]);
} }
partMap.clear(); partMap.clear();
} }
@ -247,7 +243,7 @@ public class AsyncProgramSplitter {
return Arrays.copyOf(result, result.length); return Arrays.copyOf(result, result.length);
} }
public int[] getSplitPoints(int index) { public Instruction[] getSplitPoints(int index) {
return parts.get(index).splitPoints.clone(); return parts.get(index).splitPoints.clone();
} }
@ -258,14 +254,13 @@ public class AsyncProgramSplitter {
static class Part { static class Part {
Program program; Program program;
int[] blockSuccessors; int[] blockSuccessors;
int[] splitPoints; Instruction[] splitPoints;
int[] originalBlocks; int[] originalBlocks;
public Part(int blockCount) { Part(int blockCount) {
blockSuccessors = new int[blockCount]; blockSuccessors = new int[blockCount];
Arrays.fill(blockSuccessors, -1); Arrays.fill(blockSuccessors, -1);
splitPoints = new int[blockCount]; splitPoints = new Instruction[blockCount];
Arrays.fill(splitPoints, -1);
originalBlocks = new int[blockCount]; originalBlocks = new int[blockCount];
Arrays.fill(originalBlocks, -1); Arrays.fill(originalBlocks, -1);
} }
@ -280,10 +275,10 @@ public class AsyncProgramSplitter {
private GraphSplittingBackend inner; private GraphSplittingBackend inner;
private IntegerArray blockSuccessors; private IntegerArray blockSuccessors;
private IntegerArray originalBlocks; private IntegerArray originalBlocks;
private IntegerArray splitPoints; private List<Instruction> splitPoints;
public AsyncProgramSplittingBackend(GraphSplittingBackend inner, IntegerArray blockSuccessors, public AsyncProgramSplittingBackend(GraphSplittingBackend inner, IntegerArray blockSuccessors,
IntegerArray originalBlocks, IntegerArray splitPoints) { IntegerArray originalBlocks, List<Instruction> splitPoints) {
this.inner = inner; this.inner = inner;
this.blockSuccessors = blockSuccessors; this.blockSuccessors = blockSuccessors;
this.originalBlocks = originalBlocks; this.originalBlocks = originalBlocks;
@ -298,7 +293,7 @@ public class AsyncProgramSplitter {
int node = nodes[i]; int node = nodes[i];
if (blockSuccessors.size() <= copy) { if (blockSuccessors.size() <= copy) {
blockSuccessors.add(-1); blockSuccessors.add(-1);
splitPoints.add(-1); splitPoints.add(null);
originalBlocks.add(-1); originalBlocks.add(-1);
} }
blockSuccessors.set(copy, blockSuccessors.get(node)); blockSuccessors.set(copy, blockSuccessors.get(node));

View File

@ -15,20 +15,24 @@
*/ */
package org.teavm.model.util; package org.teavm.model.util;
import java.util.function.Function;
import java.util.function.IntUnaryOperator; import java.util.function.IntUnaryOperator;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.model.instructions.*; import org.teavm.model.instructions.*;
public class BasicBlockMapper implements InstructionVisitor { public class BasicBlockMapper extends AbstractInstructionVisitor {
private IntUnaryOperator mapFunction; private Function<BasicBlock, BasicBlock> mapFunction;
public BasicBlockMapper(IntUnaryOperator mapFunction) { public BasicBlockMapper(Function<BasicBlock, BasicBlock> mapFunction) {
this.mapFunction = mapFunction; this.mapFunction = mapFunction;
} }
public BasicBlockMapper(IntUnaryOperator mapFunction) {
this((BasicBlock block) -> block.getProgram().basicBlockAt(mapFunction.applyAsInt(block.getIndex())));
}
private BasicBlock map(BasicBlock block) { private BasicBlock map(BasicBlock block) {
Program program = block.getProgram(); return mapFunction.apply(block);
return program.basicBlockAt(mapFunction.applyAsInt(block.getIndex()));
} }
public void transform(Program program) { public void transform(Program program) {
@ -54,62 +58,6 @@ public class BasicBlockMapper implements InstructionVisitor {
} }
} }
@Override
public void visit(EmptyInstruction insn) {
}
@Override
public void visit(ClassConstantInstruction insn) {
}
@Override
public void visit(NullConstantInstruction insn) {
}
@Override
public void visit(IntegerConstantInstruction insn) {
}
@Override
public void visit(LongConstantInstruction insn) {
}
@Override
public void visit(FloatConstantInstruction insn) {
}
@Override
public void visit(DoubleConstantInstruction insn) {
}
@Override
public void visit(StringConstantInstruction insn) {
}
@Override
public void visit(BinaryInstruction insn) {
}
@Override
public void visit(NegateInstruction insn) {
}
@Override
public void visit(AssignInstruction insn) {
}
@Override
public void visit(CastInstruction insn) {
}
@Override
public void visit(CastNumberInstruction insn) {
}
@Override
public void visit(CastIntegerInstruction insn) {
}
@Override @Override
public void visit(BranchingInstruction insn) { public void visit(BranchingInstruction insn) {
insn.setConsequent(map(insn.getConsequent())); insn.setConsequent(map(insn.getConsequent()));
@ -134,80 +82,4 @@ public class BasicBlockMapper implements InstructionVisitor {
} }
insn.setDefaultTarget(map(insn.getDefaultTarget())); insn.setDefaultTarget(map(insn.getDefaultTarget()));
} }
@Override
public void visit(ExitInstruction insn) {
}
@Override
public void visit(RaiseInstruction insn) {
}
@Override
public void visit(ConstructArrayInstruction insn) {
}
@Override
public void visit(ConstructInstruction insn) {
}
@Override
public void visit(ConstructMultiArrayInstruction insn) {
}
@Override
public void visit(GetFieldInstruction insn) {
}
@Override
public void visit(PutFieldInstruction insn) {
}
@Override
public void visit(ArrayLengthInstruction insn) {
}
@Override
public void visit(CloneArrayInstruction insn) {
}
@Override
public void visit(UnwrapArrayInstruction insn) {
}
@Override
public void visit(GetElementInstruction insn) {
}
@Override
public void visit(PutElementInstruction insn) {
}
@Override
public void visit(InvokeInstruction insn) {
}
@Override
public void visit(InvokeDynamicInstruction insn) {
}
@Override
public void visit(IsInstanceInstruction insn) {
}
@Override
public void visit(InitClassInstruction insn) {
}
@Override
public void visit(NullCheckInstruction insn) {
}
@Override
public void visit(MonitorEnterInstruction insn) {
}
@Override
public void visit(MonitorExitInstruction insn) {
}
} }

View File

@ -44,7 +44,7 @@ public class InstructionVariableMapper implements InstructionVisitor {
} }
public void applyToInstructions(BasicBlock block) { public void applyToInstructions(BasicBlock block) {
for (Instruction insn : block.getInstructions()) { for (Instruction insn : block) {
insn.acceptVisitor(this); insn.acceptVisitor(this);
} }
} }

View File

@ -61,8 +61,7 @@ class InterferenceGraphBuilder {
} }
} }
for (int j = block.getInstructions().size() - 1; j >= 0; --j) { for (Instruction insn = block.getLastInstruction(); insn != null; insn = insn.getPrevious()) {
Instruction insn = block.getInstructions().get(j);
insn.acceptVisitor(useExtractor); insn.acceptVisitor(useExtractor);
insn.acceptVisitor(defExtractor); insn.acceptVisitor(defExtractor);
for (Variable var : defExtractor.getDefinedVariables()) { for (Variable var : defExtractor.getDefinedVariables()) {

View File

@ -52,7 +52,7 @@ public class LivenessAnalyzer {
definitions[block.getExceptionVariable().getIndex()] = i; definitions[block.getExceptionVariable().getIndex()] = i;
} }
for (Instruction insn : block.getInstructions()) { for (Instruction insn : block) {
insn.acceptVisitor(usageExtractor); insn.acceptVisitor(usageExtractor);
IntSet usedVars = new IntOpenHashSet(); IntSet usedVars = new IntOpenHashSet();
for (Variable var : usageExtractor.getUsedVariables()) { for (Variable var : usageExtractor.getUsedVariables()) {

View File

@ -68,7 +68,7 @@ class LocationGraphBuilder {
BasicBlock block = program.basicBlockAt(step.block); BasicBlock block = program.basicBlockAt(step.block);
TextLocation location = step.location; TextLocation location = step.location;
boolean started = false; boolean started = false;
for (Instruction insn : block.getInstructions()) { for (Instruction insn : block) {
if (insn.getLocation() != null) { if (insn.getLocation() != null) {
if (!started) { if (!started) {
step.startLocations.add(insn.getLocation()); step.startLocations.add(insn.getLocation());

View File

@ -24,10 +24,6 @@ import org.teavm.model.*;
import org.teavm.model.instructions.*; import org.teavm.model.instructions.*;
import org.teavm.model.optimization.UnreachableBasicBlockEliminator; import org.teavm.model.optimization.UnreachableBasicBlockEliminator;
/**
*
* @author Alexey Andreev
*/
public class MissingItemsProcessor { public class MissingItemsProcessor {
private DependencyInfo dependencyInfo; private DependencyInfo dependencyInfo;
private Diagnostics diagnostics; private Diagnostics diagnostics;
@ -62,12 +58,11 @@ public class MissingItemsProcessor {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
instructionsToAdd.clear(); instructionsToAdd.clear();
boolean missing = false; boolean missing = false;
for (int j = 0; j < block.getInstructions().size(); ++j) { for (Instruction insn : block) {
Instruction insn = block.getInstructions().get(j);
insn.acceptVisitor(instructionProcessor); insn.acceptVisitor(instructionProcessor);
if (!instructionsToAdd.isEmpty()) { if (!instructionsToAdd.isEmpty()) {
wasModified = true; wasModified = true;
truncateBlock(block, j); truncateBlock(insn);
missing = true; missing = true;
break; break;
} }
@ -83,16 +78,19 @@ public class MissingItemsProcessor {
} }
} }
private void truncateBlock(BasicBlock block, int index) { private void truncateBlock(Instruction instruction) {
InstructionTransitionExtractor transitionExtractor = new InstructionTransitionExtractor(); InstructionTransitionExtractor transitionExtractor = new InstructionTransitionExtractor();
BasicBlock block = instruction.getBasicBlock();
if (block.getLastInstruction() != null) { if (block.getLastInstruction() != null) {
block.getLastInstruction().acceptVisitor(transitionExtractor); block.getLastInstruction().acceptVisitor(transitionExtractor);
} }
for (BasicBlock successor : transitionExtractor.getTargets()) { for (BasicBlock successor : transitionExtractor.getTargets()) {
successor.removeIncomingsFrom(block); successor.removeIncomingsFrom(block);
} }
block.getInstructions().subList(index, block.getInstructions().size()).clear(); while (instruction.getNext() != null) {
block.getInstructions().addAll(instructionsToAdd); instruction.getNext().delete();
}
instruction.insertNextAll(instructionsToAdd);
} }
private void emitExceptionThrow(TextLocation location, String exceptionName, String text) { private void emitExceptionThrow(TextLocation location, String exceptionName, String text) {

View File

@ -19,10 +19,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.teavm.model.*; import org.teavm.model.*;
/**
*
* @author Alexey Andreev
*/
public final class ModelUtils { public final class ModelUtils {
private ModelUtils() { private ModelUtils() {
} }

View File

@ -90,19 +90,29 @@ public class PhiUpdater {
private Phi[][] phiMap; private Phi[][] phiMap;
private int[][] phiIndexMap; private int[][] phiIndexMap;
private Map<TryCatchBlock, Map<Variable, TryCatchJoint>> jointMap = new HashMap<>(); private Map<TryCatchBlock, Map<Variable, TryCatchJoint>> jointMap = new HashMap<>();
private List<List<Phi>> synthesizedPhis = new ArrayList<>(); private List<List<Phi>> synthesizedPhisByBlock = new ArrayList<>();
private IntObjectMap<Phi> phisByReceiver = new IntObjectOpenHashMap<>(); private IntObjectMap<Phi> phisByReceiver = new IntObjectOpenHashMap<>();
private IntObjectMap<TryCatchJoint> jointsByReceiver = new IntObjectOpenHashMap<>(); private IntObjectMap<TryCatchJoint> jointsByReceiver = new IntObjectOpenHashMap<>();
private BitSet usedPhis = new BitSet(); private BitSet usedPhis = new BitSet();
private List<List<List<TryCatchJoint>>> synthesizedJoints = new ArrayList<>(); private List<List<List<TryCatchJoint>>> synthesizedJointsByBlock = new ArrayList<>();
private Variable[] originalExceptionVariables; private Variable[] originalExceptionVariables;
private boolean[] usedDefinitions; private boolean[] usedDefinitions;
private IntegerArray variableToSourceMap = new IntegerArray(10); private IntegerArray variableToSourceMap = new IntegerArray(10);
private List<Phi> synthesizedPhis = new ArrayList<>();
private List<TryCatchJoint> synthesizedJoints = new ArrayList<>();
public int getSourceVariable(int var) { public int getSourceVariable(int var) {
return variableToSourceMap.get(var); return variableToSourceMap.get(var);
} }
public List<Phi> getSynthesizedPhisBy() {
return synthesizedPhis;
}
public List<TryCatchJoint> getSynthesizedJoints() {
return synthesizedJoints;
}
public void updatePhis(Program program, Variable[] arguments) { public void updatePhis(Program program, Variable[] arguments) {
if (program.basicBlockCount() == 0) { if (program.basicBlockCount() == 0) {
return; return;
@ -131,15 +141,15 @@ public class PhiUpdater {
} }
domFrontiers = GraphUtils.findDominanceFrontiers(cfg, domTree); domFrontiers = GraphUtils.findDominanceFrontiers(cfg, domTree);
synthesizedPhis.clear(); synthesizedPhisByBlock.clear();
synthesizedJoints.clear(); synthesizedJointsByBlock.clear();
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
synthesizedPhis.add(new ArrayList<>()); synthesizedPhisByBlock.add(new ArrayList<>());
synthesizedJoints.add(new ArrayList<>()); synthesizedJointsByBlock.add(new ArrayList<>());
int catchCount = program.basicBlockAt(i).getTryCatchBlocks().size(); int catchCount = program.basicBlockAt(i).getTryCatchBlocks().size();
for (int j = 0; j < catchCount; ++j) { for (int j = 0; j < catchCount; ++j) {
synthesizedJoints.get(i).add(new ArrayList<>()); synthesizedJointsByBlock.get(i).add(new ArrayList<>());
} }
} }
@ -165,7 +175,7 @@ public class PhiUpdater {
markAssignment(phi.getReceiver()); markAssignment(phi.getReceiver());
} }
for (Instruction insn : currentBlock.getInstructions()) { for (Instruction insn : currentBlock) {
currentBlock = program.basicBlockAt(i); currentBlock = program.basicBlockAt(i);
insn.acceptVisitor(definitionExtractor); insn.acceptVisitor(definitionExtractor);
Set<Variable> definedVariables = new HashSet<>(); Set<Variable> definedVariables = new HashSet<>();
@ -219,7 +229,7 @@ public class PhiUpdater {
currentBlock.setExceptionVariable(define(currentBlock.getExceptionVariable())); currentBlock.setExceptionVariable(define(currentBlock.getExceptionVariable()));
} }
for (Phi phi : synthesizedPhis.get(index)) { for (Phi phi : synthesizedPhisByBlock.get(index)) {
Variable var = program.createVariable(); Variable var = program.createVariable();
var.setDebugName(phi.getReceiver().getDebugName()); var.setDebugName(phi.getReceiver().getDebugName());
mapVariable(phi.getReceiver().getIndex(), var); mapVariable(phi.getReceiver().getIndex(), var);
@ -230,7 +240,7 @@ public class PhiUpdater {
phi.setReceiver(define(phi.getReceiver())); phi.setReceiver(define(phi.getReceiver()));
} }
for (Instruction insn : currentBlock.getInstructions()) { for (Instruction insn : currentBlock) {
insn.acceptVisitor(consumer); insn.acceptVisitor(consumer);
} }
@ -256,7 +266,7 @@ public class PhiUpdater {
for (int i = 0; i < currentBlock.getTryCatchBlocks().size(); ++i) { for (int i = 0; i < currentBlock.getTryCatchBlocks().size(); ++i) {
TryCatchBlock tryCatch = currentBlock.getTryCatchBlocks().get(i); TryCatchBlock tryCatch = currentBlock.getTryCatchBlocks().get(i);
catchSuccessors.add(tryCatch.getHandler().getIndex()); catchSuccessors.add(tryCatch.getHandler().getIndex());
for (TryCatchJoint joint : synthesizedJoints.get(index).get(i)) { for (TryCatchJoint joint : synthesizedJointsByBlock.get(index).get(i)) {
Variable var = program.createVariable(); Variable var = program.createVariable();
var.setDebugName(joint.getReceiver().getDebugName()); var.setDebugName(joint.getReceiver().getDebugName());
mapVariable(joint.getReceiver().getIndex(), var); mapVariable(joint.getReceiver().getIndex(), var);
@ -284,16 +294,17 @@ public class PhiUpdater {
private void addSynthesizedPhis() { private void addSynthesizedPhis() {
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
for (Phi phi : synthesizedPhis.get(i)) { for (Phi phi : synthesizedPhisByBlock.get(i)) {
if (!usedPhis.get(phi.getReceiver().getIndex())) { if (!usedPhis.get(phi.getReceiver().getIndex())) {
continue; continue;
} }
if (!phi.getIncomings().isEmpty()) { if (!phi.getIncomings().isEmpty()) {
program.basicBlockAt(i).getPhis().add(phi); program.basicBlockAt(i).getPhis().add(phi);
synthesizedPhis.add(phi);
} }
} }
List<List<TryCatchJoint>> joints = synthesizedJoints.get(i); List<List<TryCatchJoint>> joints = synthesizedJointsByBlock.get(i);
for (int j = 0; j < joints.size(); ++j) { for (int j = 0; j < joints.size(); ++j) {
List<TryCatchJoint> jointList = joints.get(j); List<TryCatchJoint> jointList = joints.get(j);
TryCatchBlock targetTryCatch = program.basicBlockAt(i).getTryCatchBlocks().get(j); TryCatchBlock targetTryCatch = program.basicBlockAt(i).getTryCatchBlocks().get(j);
@ -303,6 +314,7 @@ public class PhiUpdater {
} }
if (!joint.getSourceVariables().isEmpty()) { if (!joint.getSourceVariables().isEmpty()) {
targetTryCatch.getJoints().add(joint); targetTryCatch.getJoints().add(joint);
synthesizedJoints.add(joint);
} }
} }
} }
@ -352,7 +364,7 @@ public class PhiUpdater {
private void renameOutgoingPhis(int successor) { private void renameOutgoingPhis(int successor) {
int[] phiIndexes = phiIndexMap[successor]; int[] phiIndexes = phiIndexMap[successor];
List<Phi> phis = synthesizedPhis.get(successor); List<Phi> phis = synthesizedPhisByBlock.get(successor);
for (int j = 0; j < phis.size(); ++j) { for (int j = 0; j < phis.size(); ++j) {
Phi phi = phis.get(j); Phi phi = phis.get(j);
@ -393,8 +405,8 @@ public class PhiUpdater {
if (phi == null) { if (phi == null) {
phi = new Phi(); phi = new Phi();
phi.setReceiver(var); phi.setReceiver(var);
phiIndexMap[frontier][synthesizedPhis.get(frontier).size()] = var.getIndex(); phiIndexMap[frontier][synthesizedPhisByBlock.get(frontier).size()] = var.getIndex();
synthesizedPhis.get(frontier).add(phi); synthesizedPhisByBlock.get(frontier).add(phi);
phiMap[frontier][var.getIndex()] = phi; phiMap[frontier][var.getIndex()] = phi;
worklist[head++] = frontierBlock; worklist[head++] = frontierBlock;
} }
@ -408,7 +420,7 @@ public class PhiUpdater {
if (joint == null) { if (joint == null) {
joint = new TryCatchJoint(); joint = new TryCatchJoint();
joint.setReceiver(var); joint.setReceiver(var);
synthesizedJoints.get(block.getIndex()).get(i).add(joint); synthesizedJointsByBlock.get(block.getIndex()).get(i).add(joint);
jointMap.get(tryCatch).put(var, joint); jointMap.get(tryCatch).put(var, joint);
worklist[head++] = tryCatch.getHandler(); worklist[head++] = tryCatch.getHandler();
} }

View File

@ -36,12 +36,11 @@ public class ProgramNodeSplittingBackend implements GraphSplittingBackend {
int node = nodes[i]; int node = nodes[i];
BasicBlock block = program.basicBlockAt(node); BasicBlock block = program.basicBlockAt(node);
BasicBlock blockCopy = program.createBasicBlock(); BasicBlock blockCopy = program.createBasicBlock();
blockCopy.getInstructions().addAll(ProgramUtils.copyInstructions(block, 0, blockCopy.addAll(ProgramUtils.copyInstructions(block.getFirstInstruction(), null, program));
block.getInstructions().size(), program));
copies[i] = blockCopy.getIndex(); copies[i] = blockCopy.getIndex();
map.put(nodes[i], copies[i] + 1); map.put(nodes[i], copies[i] + 1);
} }
BasicBlockMapper copyBlockMapper = new BasicBlockMapper(block -> { BasicBlockMapper copyBlockMapper = new BasicBlockMapper((int block) -> {
int mappedIndex = map.get(block); int mappedIndex = map.get(block);
return mappedIndex == 0 ? block : mappedIndex - 1; return mappedIndex == 0 ? block : mappedIndex - 1;
}); });

View File

@ -25,6 +25,8 @@ import org.teavm.model.BasicBlockReader;
import org.teavm.model.Incoming; import org.teavm.model.Incoming;
import org.teavm.model.IncomingReader; import org.teavm.model.IncomingReader;
import org.teavm.model.Instruction; import org.teavm.model.Instruction;
import org.teavm.model.InstructionIterator;
import org.teavm.model.InstructionReadVisitor;
import org.teavm.model.Phi; import org.teavm.model.Phi;
import org.teavm.model.PhiReader; import org.teavm.model.PhiReader;
import org.teavm.model.Program; import org.teavm.model.Program;
@ -89,17 +91,24 @@ public final class ProgramUtils {
if (block.getExceptionVariable() != null) { if (block.getExceptionVariable() != null) {
target.setExceptionVariable(targetProgram.variableAt(block.getExceptionVariable().getIndex())); target.setExceptionVariable(targetProgram.variableAt(block.getExceptionVariable().getIndex()));
} }
target.getInstructions().addAll(copyInstructions(block, 0, block.instructionCount(), targetProgram)); InstructionCopyReader copyReader = new InstructionCopyReader(targetProgram);
for (InstructionIterator iterator = block.iterateInstructions(); iterator.hasNext();) {
iterator.next();
iterator.read(copyReader);
target.add(copyReader.getCopy());
}
target.getPhis().addAll(copyPhis(block, targetProgram)); target.getPhis().addAll(copyPhis(block, targetProgram));
target.getTryCatchBlocks().addAll(copyTryCatches(block, targetProgram)); target.getTryCatchBlocks().addAll(copyTryCatches(block, targetProgram));
} }
public static List<Instruction> copyInstructions(BasicBlockReader block, int from, int to, Program target) { public static List<Instruction> copyInstructions(Instruction from, Instruction to, Program target) {
List<Instruction> result = new ArrayList<>(); List<Instruction> result = new ArrayList<>();
InstructionCopyReader copyReader = new InstructionCopyReader(target); InstructionCopyReader copyReader = new InstructionCopyReader(target);
for (int i = from; i < to; ++i) { InstructionReadVisitor visitor = new InstructionReadVisitor(copyReader);
block.readInstruction(i, copyReader); while (from != to) {
from.acceptVisitor(visitor);
result.add(copyReader.getCopy()); result.add(copyReader.getCopy());
from = from.getNext();
} }
return result; return result;
} }
@ -195,7 +204,7 @@ public final class ProgramUtils {
places[phi.getReceiver().getIndex()] = block; places[phi.getReceiver().getIndex()] = block;
} }
for (Instruction insn : block.getInstructions()) { for (Instruction insn : block) {
insn.acceptVisitor(defExtractor); insn.acceptVisitor(defExtractor);
for (Variable var : defExtractor.getDefinedVariables()) { for (Variable var : defExtractor.getDefinedVariables()) {
places[var.getIndex()] = block; places[var.getIndex()] = block;

View File

@ -37,7 +37,6 @@ import org.teavm.model.TryCatchBlock;
import org.teavm.model.TryCatchJoint; import org.teavm.model.TryCatchJoint;
import org.teavm.model.Variable; import org.teavm.model.Variable;
import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.EmptyInstruction;
import org.teavm.model.instructions.JumpInstruction; import org.teavm.model.instructions.JumpInstruction;
public class RegisterAllocator { public class RegisterAllocator {
@ -152,15 +151,16 @@ public class RegisterAllocator {
BasicBlock block = joint.getBlock().getProtectedBlock(); BasicBlock block = joint.getBlock().getProtectedBlock();
DefinitionExtractor defExtractor = new DefinitionExtractor(); DefinitionExtractor defExtractor = new DefinitionExtractor();
for (int i = block.getInstructions().size() - 1; i >= 0; --i) { Instruction nextInsn;
Instruction insn = block.getInstructions().get(i); for (Instruction insn = block.getFirstInstruction(); insn != null; insn = nextInsn) {
nextInsn = insn.getNext();
insn.acceptVisitor(defExtractor); insn.acceptVisitor(defExtractor);
for (Variable definedVar : defExtractor.getDefinedVariables()) { for (Variable definedVar : defExtractor.getDefinedVariables()) {
if (variableSet.remove(definedVar)) { if (variableSet.remove(definedVar)) {
AssignInstruction copyInsn = new AssignInstruction(); AssignInstruction copyInsn = new AssignInstruction();
copyInsn.setReceiver(joint.getReceiver()); copyInsn.setReceiver(joint.getReceiver());
copyInsn.setAssignee(definedVar); copyInsn.setAssignee(definedVar);
block.getInstructions().add(i, copyInsn); insn.insertNext(copyInsn);
} }
} }
} }
@ -169,7 +169,7 @@ public class RegisterAllocator {
AssignInstruction copyInsn = new AssignInstruction(); AssignInstruction copyInsn = new AssignInstruction();
copyInsn.setReceiver(joint.getReceiver()); copyInsn.setReceiver(joint.getReceiver());
copyInsn.setAssignee(enteringVar); copyInsn.setAssignee(enteringVar);
block.getInstructions().add(0, copyInsn); block.addFirst(copyInsn);
} }
} }
@ -206,14 +206,14 @@ public class RegisterAllocator {
final BasicBlock copyBlock = program.createBasicBlock(); final BasicBlock copyBlock = program.createBasicBlock();
JumpInstruction jumpInstruction = new JumpInstruction(); JumpInstruction jumpInstruction = new JumpInstruction();
jumpInstruction.setTarget(phi.getBasicBlock()); jumpInstruction.setTarget(phi.getBasicBlock());
copyBlock.getInstructions().add(jumpInstruction); copyBlock.add(jumpInstruction);
incoming.getSource().getLastInstruction().acceptVisitor(new BasicBlockMapper(block -> incoming.getSource().getLastInstruction().acceptVisitor(new BasicBlockMapper((int block) ->
block == phi.getBasicBlock().getIndex() ? copyBlock.getIndex() : block)); block == phi.getBasicBlock().getIndex() ? copyBlock.getIndex() : block));
blockMap.put(source, copyBlock); blockMap.put(source, copyBlock);
incoming.setSource(copyBlock); incoming.setSource(copyBlock);
source = copyBlock; source = copyBlock;
} }
source.getInstructions().add(source.getInstructions().size() - 1, copyInstruction); source.getLastInstruction().insertPrevious(copyInstruction);
incoming.setValue(copyInstruction.getReceiver()); incoming.setValue(copyInstruction.getReceiver());
} }
@ -221,8 +221,9 @@ public class RegisterAllocator {
DisjointSet congruenceClasses) { DisjointSet congruenceClasses) {
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
for (int j = 0; j < block.getInstructions().size(); ++j) { Instruction nextInsn;
Instruction insn = block.getInstructions().get(j); for (Instruction insn = block.getFirstInstruction(); insn != null; insn = nextInsn) {
nextInsn = insn.getNext();
if (!(insn instanceof AssignInstruction)) { if (!(insn instanceof AssignInstruction)) {
continue; continue;
} }
@ -242,7 +243,7 @@ public class RegisterAllocator {
} }
if (!interfere) { if (!interfere) {
int newClass = congruenceClasses.union(copyClass, origClass); int newClass = congruenceClasses.union(copyClass, origClass);
block.getInstructions().set(j, new EmptyInstruction()); insn.delete();
if (newClass == interferenceGraph.size()) { if (newClass == interferenceGraph.size()) {
MutableGraphNode newNode = new MutableGraphNode(interferenceGraph.size()); MutableGraphNode newNode = new MutableGraphNode(interferenceGraph.size());
interferenceGraph.add(newNode); interferenceGraph.add(newNode);

View File

@ -173,7 +173,7 @@ public class ClassRefsRenamer implements InstructionVisitor {
public void rename(Program program) { public void rename(Program program) {
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock basicBlock = program.basicBlockAt(i); BasicBlock basicBlock = program.basicBlockAt(i);
for (Instruction insn : basicBlock.getInstructions()) { for (Instruction insn : basicBlock) {
insn.acceptVisitor(this); insn.acceptVisitor(this);
} }
for (TryCatchBlock tryCatch : basicBlock.getTryCatchBlocks()) { for (TryCatchBlock tryCatch : basicBlock.getTryCatchBlocks()) {

View File

@ -114,7 +114,7 @@ public class Parser {
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
IntIntMap varMap = blockEntryVariableMappings[i]; IntIntMap varMap = blockEntryVariableMappings[i];
for (Instruction insn : block.getInstructions()) { for (Instruction insn : block) {
insn.acceptVisitor(defExtractor); insn.acceptVisitor(defExtractor);
Map<Integer, String> newDebugNames = parser.getDebugNames(insn); Map<Integer, String> newDebugNames = parser.getDebugNames(insn);
if (newDebugNames != null) { if (newDebugNames != null) {
@ -180,7 +180,7 @@ public class Parser {
result[node] = new IntIntOpenHashMap(varMap); result[node] = new IntIntOpenHashMap(varMap);
for (Instruction insn : block.getInstructions()) { for (Instruction insn : block) {
insn.acceptVisitor(defExtractor); insn.acceptVisitor(defExtractor);
for (Variable definedVar : defExtractor.getDefinedVariables()) { for (Variable definedVar : defExtractor.getDefinedVariables()) {
int sourceVar = phiUpdater.getSourceVariable(definedVar.getIndex()); int sourceVar = phiUpdater.getSourceVariable(definedVar.getIndex());

View File

@ -98,7 +98,7 @@ public class ProgramParser {
getBasicBlock(0); getBasicBlock(0);
JumpInstruction insn = new JumpInstruction(); JumpInstruction insn = new JumpInstruction();
insn.setTarget(program.basicBlockAt(1)); insn.setTarget(program.basicBlockAt(1));
program.basicBlockAt(0).getInstructions().add(insn); program.basicBlockAt(0).add(insn);
doAnalyze(method); doAnalyze(method);
assemble(method); assemble(method);
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
@ -271,12 +271,12 @@ public class ProgramParser {
if (basicBlock != null && !hasProperLastInstruction(basicBlock)) { if (basicBlock != null && !hasProperLastInstruction(basicBlock)) {
JumpInstruction insn = new JumpInstruction(); JumpInstruction insn = new JumpInstruction();
insn.setTarget(newBasicBlock); insn.setTarget(newBasicBlock);
basicBlock.getInstructions().add(insn); basicBlock.add(insn);
} }
basicBlock = newBasicBlock; basicBlock = newBasicBlock;
if (!basicBlock.getInstructions().isEmpty()) { if (basicBlock.instructionCount() > 0) {
Map<Integer, String> debugNames = new HashMap<>(accumulatedDebugNames); Map<Integer, String> debugNames = new HashMap<>(accumulatedDebugNames);
variableDebugNames.put(basicBlock.getInstructions().get(0), debugNames); variableDebugNames.put(basicBlock.getFirstInstruction(), debugNames);
} }
} }
List<Instruction> builtInstructions = targetInstructions.get(i); List<Instruction> builtInstructions = targetInstructions.get(i);
@ -305,7 +305,7 @@ public class ProgramParser {
for (Instruction insn : builtInstructions) { for (Instruction insn : builtInstructions) {
insn.setLocation(lastLocation); insn.setLocation(lastLocation);
} }
basicBlock.getInstructions().addAll(builtInstructions); basicBlock.addAll(builtInstructions);
} }
} }
} }
@ -1704,6 +1704,7 @@ public class ProgramParser {
PutFieldInstruction insn = new PutFieldInstruction(); PutFieldInstruction insn = new PutFieldInstruction();
insn.setField(referenceCache.getCached(new FieldReference(ownerCls, name))); insn.setField(referenceCache.getCached(new FieldReference(ownerCls, name)));
insn.setValue(getVariable(value)); insn.setValue(getVariable(value));
insn.setFieldType(referenceCache.parseValueTypeCached(desc));
addInstruction(insn); addInstruction(insn);
break; break;
} }

View File

@ -27,26 +27,23 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.junit.Test; import org.junit.Test;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
import org.teavm.model.Instruction;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
import org.teavm.model.instructions.*; import org.teavm.model.instructions.*;
/**
*
* @author Alexey Andreev
*/
public class ProgramIOTest { public class ProgramIOTest {
@Test @Test
public void emptyInstruction() { public void emptyInstruction() {
Program program = new Program(); Program program = new Program();
BasicBlock block = program.createBasicBlock(); BasicBlock block = program.createBasicBlock();
block.getInstructions().add(new EmptyInstruction()); block.add(new EmptyInstruction());
program = inputOutput(program); program = inputOutput(program);
block = program.basicBlockAt(0); block = program.basicBlockAt(0);
assertThat(block.getInstructions().size(), is(1)); assertThat(block.instructionCount(), is(1));
assertThat(block.getInstructions().get(0), instanceOf(EmptyInstruction.class)); assertThat(block.getFirstInstruction(), instanceOf(EmptyInstruction.class));
} }
@Test @Test
@ -56,67 +53,81 @@ public class ProgramIOTest {
ClassConstantInstruction classConstInsn = new ClassConstantInstruction(); ClassConstantInstruction classConstInsn = new ClassConstantInstruction();
classConstInsn.setConstant(ValueType.BYTE); classConstInsn.setConstant(ValueType.BYTE);
classConstInsn.setReceiver(program.createVariable()); classConstInsn.setReceiver(program.createVariable());
block.getInstructions().add(classConstInsn); block.add(classConstInsn);
NullConstantInstruction nullConstInsn = new NullConstantInstruction(); NullConstantInstruction nullConstInsn = new NullConstantInstruction();
nullConstInsn.setReceiver(program.createVariable()); nullConstInsn.setReceiver(program.createVariable());
block.getInstructions().add(nullConstInsn); block.add(nullConstInsn);
IntegerConstantInstruction intConsInsn = new IntegerConstantInstruction(); IntegerConstantInstruction intConsInsn = new IntegerConstantInstruction();
intConsInsn.setReceiver(program.createVariable()); intConsInsn.setReceiver(program.createVariable());
intConsInsn.setConstant(23); intConsInsn.setConstant(23);
block.getInstructions().add(intConsInsn); block.add(intConsInsn);
LongConstantInstruction longConsInsn = new LongConstantInstruction(); LongConstantInstruction longConsInsn = new LongConstantInstruction();
longConsInsn.setReceiver(program.createVariable()); longConsInsn.setReceiver(program.createVariable());
longConsInsn.setConstant(234); longConsInsn.setConstant(234);
block.getInstructions().add(longConsInsn); block.add(longConsInsn);
FloatConstantInstruction floatConsInsn = new FloatConstantInstruction(); FloatConstantInstruction floatConsInsn = new FloatConstantInstruction();
floatConsInsn.setReceiver(program.createVariable()); floatConsInsn.setReceiver(program.createVariable());
floatConsInsn.setConstant(3.14f); floatConsInsn.setConstant(3.14f);
block.getInstructions().add(floatConsInsn); block.add(floatConsInsn);
DoubleConstantInstruction doubleConsInsn = new DoubleConstantInstruction(); DoubleConstantInstruction doubleConsInsn = new DoubleConstantInstruction();
doubleConsInsn.setReceiver(program.createVariable()); doubleConsInsn.setReceiver(program.createVariable());
doubleConsInsn.setConstant(3.14159); doubleConsInsn.setConstant(3.14159);
block.getInstructions().add(doubleConsInsn); block.add(doubleConsInsn);
StringConstantInstruction stringConsInsn = new StringConstantInstruction(); StringConstantInstruction stringConsInsn = new StringConstantInstruction();
stringConsInsn.setReceiver(program.createVariable()); stringConsInsn.setReceiver(program.createVariable());
stringConsInsn.setConstant("foo"); stringConsInsn.setConstant("foo");
block.getInstructions().add(stringConsInsn); block.add(stringConsInsn);
program = inputOutput(program); program = inputOutput(program);
block = program.basicBlockAt(0); block = program.basicBlockAt(0);
assertThat(block.getInstructions().size(), is(7)); assertThat(block.instructionCount(), is(7));
assertThat(block.getInstructions().get(0), instanceOf(ClassConstantInstruction.class)); Instruction insn = block.getFirstInstruction();
assertThat(block.getInstructions().get(1), instanceOf(NullConstantInstruction.class)); assertThat(insn, instanceOf(ClassConstantInstruction.class));
assertThat(block.getInstructions().get(2), instanceOf(IntegerConstantInstruction.class)); insn = insn.getNext();
assertThat(block.getInstructions().get(3), instanceOf(LongConstantInstruction.class)); assertThat(insn, instanceOf(NullConstantInstruction.class));
assertThat(block.getInstructions().get(4), instanceOf(FloatConstantInstruction.class)); insn = insn.getNext();
assertThat(block.getInstructions().get(5), instanceOf(DoubleConstantInstruction.class)); assertThat(insn, instanceOf(IntegerConstantInstruction.class));
assertThat(block.getInstructions().get(6), instanceOf(StringConstantInstruction.class)); insn = insn.getNext();
assertThat(insn, instanceOf(LongConstantInstruction.class));
insn = insn.getNext();
assertThat(insn, instanceOf(FloatConstantInstruction.class));
insn = insn.getNext();
assertThat(insn, instanceOf(DoubleConstantInstruction.class));
insn = insn.getNext();
assertThat(insn, instanceOf(StringConstantInstruction.class));
classConstInsn = (ClassConstantInstruction)block.getInstructions().get(0); insn = block.getFirstInstruction();
classConstInsn = (ClassConstantInstruction) insn;
assertThat(classConstInsn.getReceiver().getIndex(), is(0)); assertThat(classConstInsn.getReceiver().getIndex(), is(0));
assertThat(classConstInsn.getConstant().toString(), is(ValueType.BYTE.toString())); assertThat(classConstInsn.getConstant().toString(), is(ValueType.BYTE.toString()));
nullConstInsn = (NullConstantInstruction)block.getInstructions().get(1); insn = insn.getNext();
nullConstInsn = (NullConstantInstruction) insn;
assertThat(nullConstInsn.getReceiver().getIndex(), is(1)); assertThat(nullConstInsn.getReceiver().getIndex(), is(1));
intConsInsn = (IntegerConstantInstruction)block.getInstructions().get(2); insn = insn.getNext();
intConsInsn = (IntegerConstantInstruction) insn;
assertThat(intConsInsn.getConstant(), is(23)); assertThat(intConsInsn.getConstant(), is(23));
assertThat(intConsInsn.getReceiver().getIndex(), is(2)); assertThat(intConsInsn.getReceiver().getIndex(), is(2));
longConsInsn = (LongConstantInstruction)block.getInstructions().get(3); insn = insn.getNext();
longConsInsn = (LongConstantInstruction) insn;
assertThat(longConsInsn.getConstant(), is(234L)); assertThat(longConsInsn.getConstant(), is(234L));
assertThat(longConsInsn.getReceiver().getIndex(), is(3)); assertThat(longConsInsn.getReceiver().getIndex(), is(3));
floatConsInsn = (FloatConstantInstruction)block.getInstructions().get(4); insn = insn.getNext();
floatConsInsn = (FloatConstantInstruction) insn;
assertThat(floatConsInsn.getConstant(), is(3.14f)); assertThat(floatConsInsn.getConstant(), is(3.14f));
assertThat(floatConsInsn.getReceiver().getIndex(), is(4)); assertThat(floatConsInsn.getReceiver().getIndex(), is(4));
doubleConsInsn = (DoubleConstantInstruction)block.getInstructions().get(5); insn = insn.getNext();
doubleConsInsn = (DoubleConstantInstruction) insn;
assertThat(doubleConsInsn.getConstant(), is(3.14159)); assertThat(doubleConsInsn.getConstant(), is(3.14159));
assertThat(doubleConsInsn.getReceiver().getIndex(), is(5)); assertThat(doubleConsInsn.getReceiver().getIndex(), is(5));
stringConsInsn = (StringConstantInstruction)block.getInstructions().get(6); insn = insn.getNext();
stringConsInsn = (StringConstantInstruction) insn;
assertThat(stringConsInsn.getConstant(), is("foo")); assertThat(stringConsInsn.getConstant(), is("foo"));
assertThat(stringConsInsn.getReceiver().getIndex(), is(6)); assertThat(stringConsInsn.getReceiver().getIndex(), is(6));
} }
@ -128,39 +139,23 @@ public class ProgramIOTest {
IntegerConstantInstruction constInsn = new IntegerConstantInstruction(); IntegerConstantInstruction constInsn = new IntegerConstantInstruction();
constInsn.setConstant(3); constInsn.setConstant(3);
constInsn.setReceiver(program.createVariable()); constInsn.setReceiver(program.createVariable());
block.getInstructions().add(constInsn); block.add(constInsn);
constInsn = new IntegerConstantInstruction(); constInsn = new IntegerConstantInstruction();
constInsn.setConstant(2); constInsn.setConstant(2);
constInsn.setReceiver(program.createVariable()); constInsn.setReceiver(program.createVariable());
block.getInstructions().add(constInsn); block.add(constInsn);
BinaryInstruction addInsn = new BinaryInstruction(BinaryOperation.ADD, NumericOperandType.INT); BinaryInstruction addInsn = new BinaryInstruction(BinaryOperation.ADD, NumericOperandType.INT);
addInsn.setFirstOperand(program.variableAt(0)); addInsn.setFirstOperand(program.variableAt(0));
addInsn.setSecondOperand(program.variableAt(1)); addInsn.setSecondOperand(program.variableAt(1));
addInsn.setReceiver(program.createVariable()); addInsn.setReceiver(program.createVariable());
block.getInstructions().add(addInsn); block.add(addInsn);
BinaryInstruction subInsn = new BinaryInstruction(BinaryOperation.SUBTRACT, NumericOperandType.INT); BinaryInstruction subInsn = new BinaryInstruction(BinaryOperation.SUBTRACT, NumericOperandType.INT);
subInsn.setFirstOperand(program.variableAt(2)); subInsn.setFirstOperand(program.variableAt(2));
subInsn.setSecondOperand(program.variableAt(0)); subInsn.setSecondOperand(program.variableAt(0));
subInsn.setReceiver(program.createVariable()); subInsn.setReceiver(program.createVariable());
block.getInstructions().add(subInsn); block.add(subInsn);
assertThat(block.getInstructions().size(), is(4)); assertThat(block.instructionCount(), is(4));
assertThat(block.getInstructions().get(2), instanceOf(BinaryInstruction.class));
assertThat(block.getInstructions().get(3), instanceOf(BinaryInstruction.class));
addInsn = (BinaryInstruction)block.getInstructions().get(2);
assertThat(addInsn.getOperation(), is(BinaryOperation.ADD));
assertThat(addInsn.getOperandType(), is(NumericOperandType.INT));
assertThat(addInsn.getFirstOperand().getIndex(), is(0));
assertThat(addInsn.getSecondOperand().getIndex(), is(1));
assertThat(addInsn.getReceiver().getIndex(), is(2));
subInsn = (BinaryInstruction)block.getInstructions().get(3);
assertThat(subInsn.getOperation(), is(BinaryOperation.SUBTRACT));
assertThat(subInsn.getOperandType(), is(NumericOperandType.INT));
assertThat(subInsn.getFirstOperand().getIndex(), is(2));
assertThat(subInsn.getSecondOperand().getIndex(), is(0));
assertThat(subInsn.getReceiver().getIndex(), is(3));
} }
private Program inputOutput(Program program) { private Program inputOutput(Program program) {

View File

@ -16,9 +16,6 @@
package org.teavm.model.text; package org.teavm.model.text;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
@ -26,20 +23,6 @@ import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.instructions.CastInstruction;
import org.teavm.model.instructions.CastIntegerInstruction;
import org.teavm.model.instructions.CastNumberInstruction;
import org.teavm.model.instructions.ClassConstantInstruction;
import org.teavm.model.instructions.ConstructArrayInstruction;
import org.teavm.model.instructions.ConstructInstruction;
import org.teavm.model.instructions.ConstructMultiArrayInstruction;
import org.teavm.model.instructions.DoubleConstantInstruction;
import org.teavm.model.instructions.FloatConstantInstruction;
import org.teavm.model.instructions.IntegerConstantInstruction;
import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.LongConstantInstruction;
import org.teavm.model.instructions.StringConstantInstruction;
public class ParserTest { public class ParserTest {
@Test @Test
@ -47,8 +30,8 @@ public class ParserTest {
Program program = runTest("simple"); Program program = runTest("simple");
assertEquals(2, program.basicBlockCount()); assertEquals(2, program.basicBlockCount());
assertEquals(4, program.variableCount()); assertEquals(4, program.variableCount());
assertEquals(4, program.basicBlockAt(0).getInstructions().size()); assertEquals(4, program.basicBlockAt(0).instructionCount());
assertEquals(1, program.basicBlockAt(1).getInstructions().size()); assertEquals(1, program.basicBlockAt(1).instructionCount());
} }
@Test @Test
@ -56,7 +39,7 @@ public class ParserTest {
Program program = runTest("conditional"); Program program = runTest("conditional");
assertEquals(7, program.basicBlockCount()); assertEquals(7, program.basicBlockCount());
for (int i = 0; i < 7; ++i) { for (int i = 0; i < 7; ++i) {
assertEquals(1, program.basicBlockAt(i).getInstructions().size()); assertEquals(1, program.basicBlockAt(i).instructionCount());
} }
} }
@ -73,51 +56,19 @@ public class ParserTest {
assertEquals(1, program.basicBlockCount()); assertEquals(1, program.basicBlockCount());
BasicBlock block = program.basicBlockAt(0); BasicBlock block = program.basicBlockAt(0);
assertEquals(7, block.getInstructions().size()); assertEquals(7, block.instructionCount());
assertTrue("IntConstant", block.getInstructions().get(0) instanceof IntegerConstantInstruction);
assertTrue("LongConstant", block.getInstructions().get(1) instanceof LongConstantInstruction);
assertTrue("FloatConstant", block.getInstructions().get(2) instanceof FloatConstantInstruction);
assertTrue("DoubleConstant", block.getInstructions().get(3) instanceof DoubleConstantInstruction);
assertTrue("StringConstant", block.getInstructions().get(4) instanceof StringConstantInstruction);
assertTrue("ClassConstant", block.getInstructions().get(5) instanceof ClassConstantInstruction);
} }
@Test @Test
public void invocation() throws Exception { public void invocation() throws Exception {
Program program = runTest("invocation"); Program program = runTest("invocation");
assertEquals(1, program.basicBlockCount()); assertEquals(1, program.basicBlockCount());
BasicBlock block = program.basicBlockAt(0);
assertTrue(block.getInstructions().get(0) instanceof InvokeInstruction);
assertTrue(block.getInstructions().get(1) instanceof InvokeInstruction);
assertTrue(block.getInstructions().get(2) instanceof InvokeInstruction);
InvokeInstruction invoke = (InvokeInstruction) block.getInstructions().get(0);
assertEquals(InvocationType.VIRTUAL, invoke.getType());
assertEquals(0, invoke.getArguments().size());
assertNotNull(invoke.getInstance());
invoke = (InvokeInstruction) block.getInstructions().get(1);
assertEquals(InvocationType.SPECIAL, invoke.getType());
assertEquals(1, invoke.getArguments().size());
assertNull(invoke.getInstance());
invoke = (InvokeInstruction) block.getInstructions().get(2);
assertEquals(InvocationType.SPECIAL, invoke.getType());
assertEquals(1, invoke.getArguments().size());
assertNotNull(invoke.getInstance());
} }
@Test @Test
public void casting() throws Exception { public void casting() throws Exception {
Program program = runTest("casting"); Program program = runTest("casting");
assertEquals(1, program.basicBlockCount()); assertEquals(1, program.basicBlockCount());
BasicBlock block = program.basicBlockAt(0);
assertTrue(block.getInstructions().get(0) instanceof CastInstruction);
assertTrue(block.getInstructions().get(1) instanceof CastIntegerInstruction);
assertTrue(block.getInstructions().get(2) instanceof CastIntegerInstruction);
assertTrue(block.getInstructions().get(3) instanceof CastNumberInstruction);
} }
@Test @Test
@ -129,11 +80,6 @@ public class ParserTest {
public void create() throws Exception { public void create() throws Exception {
Program program = runTest("create"); Program program = runTest("create");
assertEquals(1, program.basicBlockCount()); assertEquals(1, program.basicBlockCount());
BasicBlock block = program.basicBlockAt(0);
assertTrue(block.getInstructions().get(0) instanceof ConstructInstruction);
assertTrue(block.getInstructions().get(1) instanceof ConstructArrayInstruction);
assertTrue(block.getInstructions().get(2) instanceof ConstructMultiArrayInstruction);
} }
@Test @Test

View File

@ -19,10 +19,6 @@ import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.model.instructions.*; import org.teavm.model.instructions.*;
/**
*
* @author Alexey Andreev
*/
public class JCLHacks implements ClassHolderTransformer { public class JCLHacks implements ClassHolderTransformer {
@Override @Override
public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) {
@ -32,39 +28,33 @@ public class JCLHacks implements ClassHolderTransformer {
} }
private void installThreadMethods(ClassHolder cls) { private void installThreadMethods(ClassHolder cls) {
cls.addMethod(createMethodThrowingSecurityException(new MethodDescriptor("setName", String.class, void.class), cls.addMethod(createMethodThrowingSecurityException(new MethodDescriptor("setName", String.class, void.class)));
false));
cls.addMethod(createMethodThrowingSecurityException(new MethodDescriptor("setDaemon", cls.addMethod(createMethodThrowingSecurityException(new MethodDescriptor("setDaemon",
boolean.class, void.class), false)); boolean.class, void.class)));
} }
private MethodHolder createMethodThrowingSecurityException(MethodDescriptor desc, boolean staticMethod) { private MethodHolder createMethodThrowingSecurityException(MethodDescriptor desc) {
MethodHolder method = new MethodHolder(desc); MethodHolder method = new MethodHolder(desc);
Program program = new Program(); Program program = new Program();
for (int i = 0; i < desc.parameterCount(); ++i) { for (int i = 0; i < desc.parameterCount(); ++i) {
program.createVariable(); program.createVariable();
} }
if (!staticMethod) {
program.createVariable(); program.createVariable();
}
program.createVariable(); program.createVariable();
Variable var = program.createVariable(); Variable var = program.createVariable();
BasicBlock block = program.createBasicBlock(); BasicBlock block = program.createBasicBlock();
ConstructInstruction cons = new ConstructInstruction(); ConstructInstruction cons = new ConstructInstruction();
cons.setType("java.lang.SecurityException"); cons.setType("java.lang.SecurityException");
cons.setReceiver(var); cons.setReceiver(var);
block.getInstructions().add(cons); block.add(cons);
InvokeInstruction invoke = new InvokeInstruction(); InvokeInstruction invoke = new InvokeInstruction();
invoke.setType(InvocationType.SPECIAL); invoke.setType(InvocationType.SPECIAL);
invoke.setInstance(var); invoke.setInstance(var);
invoke.setMethod(new MethodReference(SecurityException.class, "<init>", void.class)); invoke.setMethod(new MethodReference(SecurityException.class, "<init>", void.class));
block.getInstructions().add(invoke); block.add(invoke);
RaiseInstruction raise = new RaiseInstruction(); RaiseInstruction raise = new RaiseInstruction();
raise.setException(var); raise.setException(var);
block.getInstructions().add(raise); block.add(raise);
if (staticMethod) {
method.getModifiers().add(ElementModifier.STATIC);
}
method.setLevel(AccessLevel.PUBLIC); method.setLevel(AccessLevel.PUBLIC);
method.setProgram(program); method.setProgram(program);
return method; return method;

View File

@ -270,9 +270,7 @@ class JSClassProcessor {
program = methodToProcess.getProgram(); program = methodToProcess.getProgram();
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
List<Instruction> instructions = block.getInstructions(); for (Instruction insn : block) {
for (int j = 0; j < instructions.size(); ++j) {
Instruction insn = instructions.get(j);
if (!(insn instanceof InvokeInstruction)) { if (!(insn instanceof InvokeInstruction)) {
continue; continue;
} }
@ -285,9 +283,8 @@ class JSClassProcessor {
CallLocation callLocation = new CallLocation(methodToProcess.getReference(), insn.getLocation()); CallLocation callLocation = new CallLocation(methodToProcess.getReference(), insn.getLocation());
replacement.clear(); replacement.clear();
if (processInvocation(method, callLocation, invoke, methodToProcess)) { if (processInvocation(method, callLocation, invoke, methodToProcess)) {
block.getInstructions().set(j, replacement.get(0)); insn.insertNextAll(replacement);
block.getInstructions().addAll(j + 1, replacement.subList(1, replacement.size())); insn.delete();
j += replacement.size() - 1;
} }
} }
} }
@ -657,16 +654,16 @@ class JSClassProcessor {
if (callee.getResultType() != ValueType.VOID) { if (callee.getResultType() != ValueType.VOID) {
insn.setReceiver(program.createVariable()); insn.setReceiver(program.createVariable());
} }
block.getInstructions().addAll(replacement); block.addAll(replacement);
block.getInstructions().add(insn); block.add(insn);
ExitInstruction exit = new ExitInstruction(); ExitInstruction exit = new ExitInstruction();
if (insn.getReceiver() != null) { if (insn.getReceiver() != null) {
replacement.clear(); replacement.clear();
exit.setValueToReturn(wrap(insn.getReceiver(), callee.getResultType(), null)); exit.setValueToReturn(wrap(insn.getReceiver(), callee.getResultType(), null));
block.getInstructions().addAll(replacement); block.addAll(replacement);
} }
block.getInstructions().add(exit); block.add(exit);
callerMethod.setProgram(program); callerMethod.setProgram(program);
cls.addMethod(callerMethod); cls.addMethod(callerMethod);

View File

@ -197,13 +197,14 @@ public class CompositeMethodGenerator {
templateBlock.readAllInstructions(substitutor); templateBlock.readAllInstructions(substitutor);
// Capture phi inputs of successor blocks // Capture phi inputs of successor blocks
Instruction lastInsn = targetBlock.getInstructions().remove(targetBlock.getInstructions().size() - 1); Instruction lastInsn = targetBlock.getLastInstruction();
lastInsn.delete();
List<Incoming> blockOutgoings = outgoings.get(i); List<Incoming> blockOutgoings = outgoings.get(i);
for (int j = 0; j < blockOutgoings.size(); ++j) { for (int j = 0; j < blockOutgoings.size(); ++j) {
VariableReader outgoingVar = outgoingVars.get(i).get(j); VariableReader outgoingVar = outgoingVars.get(i).get(j);
blockOutgoings.get(j).setValue(substitutor.var(outgoingVar)); blockOutgoings.get(j).setValue(substitutor.var(outgoingVar));
} }
targetBlock.getInstructions().add(lastInsn); targetBlock.add(lastInsn);
phiBlockMap.put(targetBlock, currentBlock()); phiBlockMap.put(targetBlock, currentBlock());
} }
@ -235,7 +236,7 @@ public class CompositeMethodGenerator {
void add(Instruction insn) { void add(Instruction insn) {
insn.setLocation(forcedLocation != null ? forcedLocation : location); insn.setLocation(forcedLocation != null ? forcedLocation : location);
program.basicBlockAt(blockIndex).getInstructions().add(insn); program.basicBlockAt(blockIndex).add(insn);
} }
Variable captureValue(CapturedValue captured) { Variable captureValue(CapturedValue captured) {

View File

@ -278,7 +278,7 @@ public final class MetaprogrammingImpl {
JumpInstruction jumpToStart = new JumpInstruction(); JumpInstruction jumpToStart = new JumpInstruction();
jumpToStart.setTarget(program.basicBlockAt(startBlock.getIndex() + 1)); jumpToStart.setTarget(program.basicBlockAt(startBlock.getIndex() + 1));
startBlock.getInstructions().add(jumpToStart); startBlock.add(jumpToStart);
new Optimizations().apply(program); new Optimizations().apply(program);
cls.addMethod(methodHolder); cls.addMethod(methodHolder);

View File

@ -83,7 +83,7 @@ public class ProxyVariableContext extends VariableContext {
insn.setField(capturedValue.field.getReference()); insn.setField(capturedValue.field.getReference());
insn.setFieldType(capturedValue.field.getType()); insn.setFieldType(capturedValue.field.getType());
insn.setReceiver(var); insn.setReceiver(var);
startBlock.getInstructions().add(insn); startBlock.add(insn);
return var; return var;
} }
@ -105,7 +105,7 @@ public class ProxyVariableContext extends VariableContext {
invokeSuper.setInstance(ctorProgram.createVariable()); invokeSuper.setInstance(ctorProgram.createVariable());
invokeSuper.setMethod(new MethodReference(proxyClass.getParent(), "<init>", ValueType.VOID)); invokeSuper.setMethod(new MethodReference(proxyClass.getParent(), "<init>", ValueType.VOID));
invokeSuper.setType(InvocationType.SPECIAL); invokeSuper.setType(InvocationType.SPECIAL);
ctorBlock.getInstructions().add(invokeSuper); ctorBlock.add(invokeSuper);
for (int i = 0; i < capturedValues.size(); ++i) { for (int i = 0; i < capturedValues.size(); ++i) {
PutFieldInstruction putInsn = new PutFieldInstruction(); PutFieldInstruction putInsn = new PutFieldInstruction();
@ -113,11 +113,11 @@ public class ProxyVariableContext extends VariableContext {
putInsn.setFieldType(capturedValues.get(i).field.getType()); putInsn.setFieldType(capturedValues.get(i).field.getType());
putInsn.setValue(ctorProgram.createVariable()); putInsn.setValue(ctorProgram.createVariable());
putInsn.setInstance(ctorProgram.variableAt(0)); putInsn.setInstance(ctorProgram.variableAt(0));
ctorBlock.getInstructions().add(putInsn); ctorBlock.add(putInsn);
} }
ExitInstruction exit = new ExitInstruction(); ExitInstruction exit = new ExitInstruction();
ctorBlock.getInstructions().add(exit); ctorBlock.add(exit);
proxyClass.addMethod(ctor); proxyClass.addMethod(ctor);

View File

@ -320,7 +320,7 @@ class UsageGenerator {
var = program.createVariable(); var = program.createVariable();
insn.setReceiver(var); insn.setReceiver(var);
block.getInstructions().add(insn); block.add(insn);
return var; return var;
} }
} }

View File

@ -16,11 +16,11 @@
package org.teavm.metaprogramming.impl.optimization; package org.teavm.metaprogramming.impl.optimization;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.teavm.common.DisjointSet; import org.teavm.common.DisjointSet;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
import org.teavm.model.Incoming; import org.teavm.model.Incoming;
@ -39,8 +39,8 @@ import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.util.UsageExtractor; import org.teavm.model.util.UsageExtractor;
public class BoxingElimination { public class BoxingElimination {
private static Set<String> wrapperClasses = Arrays.asList(Boolean.class, Byte.class, Short.class, private static Set<String> wrapperClasses = Stream.of(Boolean.class, Byte.class, Short.class,
Character.class, Integer.class, Long.class, Float.class, Double.class).stream() Character.class, Integer.class, Long.class, Float.class, Double.class)
.map(Class::getName) .map(Class::getName)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
private DisjointSet set = new DisjointSet(); private DisjointSet set = new DisjointSet();
@ -67,7 +67,7 @@ public class BoxingElimination {
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) { for (Instruction insn : block) {
if (insn instanceof AssignInstruction) { if (insn instanceof AssignInstruction) {
AssignInstruction assign = (AssignInstruction) insn; AssignInstruction assign = (AssignInstruction) insn;
union(assign.getReceiver().getIndex(), assign.getAssignee().getIndex()); union(assign.getReceiver().getIndex(), assign.getAssignee().getIndex());
@ -125,15 +125,14 @@ public class BoxingElimination {
private void removeInstructions() { private void removeInstructions() {
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
for (int j = 0; j < block.getInstructions().size(); ++j) { for (Instruction insn : block) {
Instruction insn = block.getInstructions().get(j);
if (insn instanceof CastInstruction) { if (insn instanceof CastInstruction) {
CastInstruction cast = (CastInstruction) insn; CastInstruction cast = (CastInstruction) insn;
if (isProven(cast.getReceiver().getIndex())) { if (isProven(cast.getReceiver().getIndex())) {
AssignInstruction assign = new AssignInstruction(); AssignInstruction assign = new AssignInstruction();
assign.setReceiver(cast.getReceiver()); assign.setReceiver(cast.getReceiver());
assign.setAssignee(cast.getValue()); assign.setAssignee(cast.getValue());
block.getInstructions().set(j, assign); insn.replace(assign);
} }
} else if (insn instanceof InvokeInstruction) { } else if (insn instanceof InvokeInstruction) {
InvokeInstruction invoke = (InvokeInstruction) insn; InvokeInstruction invoke = (InvokeInstruction) insn;
@ -141,12 +140,12 @@ public class BoxingElimination {
AssignInstruction assign = new AssignInstruction(); AssignInstruction assign = new AssignInstruction();
assign.setReceiver(invoke.getReceiver()); assign.setReceiver(invoke.getReceiver());
assign.setAssignee(invoke.getArguments().get(0)); assign.setAssignee(invoke.getArguments().get(0));
block.getInstructions().set(j, assign); insn.replace(assign);
} else if (invoke.getInstance() != null && isProven(invoke.getInstance().getIndex())) { } else if (invoke.getInstance() != null && isProven(invoke.getInstance().getIndex())) {
AssignInstruction assign = new AssignInstruction(); AssignInstruction assign = new AssignInstruction();
assign.setReceiver(invoke.getReceiver()); assign.setReceiver(invoke.getReceiver());
assign.setAssignee(invoke.getInstance()); assign.setAssignee(invoke.getInstance());
block.getInstructions().set(j, assign); insn.replace(assign);
} }
} }
} }

View File

@ -22,10 +22,6 @@ import org.teavm.platform.metadata.Resource;
import org.teavm.platform.metadata.ResourceArray; import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap; import org.teavm.platform.metadata.ResourceMap;
/**
*
* @author Alexey Andreev
*/
class ResourceProgramTransformer { class ResourceProgramTransformer {
private ClassReaderSource innerSource; private ClassReaderSource innerSource;
private Program program; private Program program;
@ -42,16 +38,13 @@ class ResourceProgramTransformer {
} }
private void transformBasicBlock(BasicBlock block) { private void transformBasicBlock(BasicBlock block) {
List<Instruction> instructions = block.getInstructions(); for (Instruction insn : block) {
for (int i = 0; i < instructions.size(); ++i) {
Instruction insn = instructions.get(i);
if (insn instanceof InvokeInstruction) { if (insn instanceof InvokeInstruction) {
InvokeInstruction invoke = (InvokeInstruction) insn; InvokeInstruction invoke = (InvokeInstruction) insn;
List<Instruction> replacement = transformInvoke(invoke); List<Instruction> replacement = transformInvoke(invoke);
if (replacement != null) { if (replacement != null) {
instructions.set(i, new EmptyInstruction()); insn.insertNextAll(replacement);
instructions.addAll(i, replacement); insn.delete();
i += replacement.size();
} }
} }
} }