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.InvokeInstruction;
/**
*
* @author Alexey Andreev
*/
public class JavacSupport implements ClassHolderTransformer {
@Override
public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) {
@ -39,15 +35,15 @@ public class JavacSupport implements ClassHolderTransformer {
ConstructInstruction construct = new ConstructInstruction();
construct.setReceiver(var);
construct.setType("com.sun.tools.javac.api.JavacTool");
block.getInstructions().add(construct);
block.add(construct);
InvokeInstruction init = new InvokeInstruction();
init.setInstance(var);
init.setType(InvocationType.SPECIAL);
init.setMethod(new MethodReference("com.sun.tools.javac.api.JavacTool", "<init>", ValueType.VOID));
block.getInstructions().add(init);
block.add(init);
ExitInstruction exit = new ExitInstruction();
exit.setValueToReturn(var);
block.getInstructions().add(exit);
block.add(exit);
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;
import java.util.List;
import java.util.Properties;
import org.teavm.diagnostics.Diagnostics;
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.PutFieldInstruction;
/**
*
* @author Alexey Andreev
*/
public class ScalaHacks implements ClassHolderTransformer {
private static final String ATTR_NAME_CLASS = "java.util.jar.Attributes$Name";
@Override
@ -56,16 +66,14 @@ public class ScalaHacks implements ClassHolderTransformer {
Program program = method.getProgram();
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
List<Instruction> instructions = block.getInstructions();
for (int j = 0; j < instructions.size(); ++j) {
Instruction insn = instructions.get(j);
for (Instruction insn : block) {
if (insn instanceof InvokeInstruction) {
if (((InvokeInstruction) insn).getMethod().getClassName().equals(ATTR_NAME_CLASS)) {
instructions.remove(j--);
insn.delete();
}
} else if (insn instanceof PutFieldInstruction) {
if (((PutFieldInstruction) insn).getField().getFieldName().equals("ScalaCompilerVersion")) {
instructions.remove(j--);
insn.delete();
}
} else if (insn instanceof ConstructInstruction) {
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;
import java.util.Arrays;
@ -18,12 +33,8 @@ import org.teavm.model.ValueType;
import org.teavm.model.emit.ProgramEmitter;
import org.teavm.model.emit.ValueEmitter;
/**
*
* @author Alexey Andreev
*/
public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor {
private int lambdaIndex = 0;
private int lambdaIndex;
@Override
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.platform.Platform;
/**
*
* @author Alexey Andreev
*/
class TConsoleOutputStreamStdout extends TOutputStream {
@Override
@DelegateTo("writeLowLevel")

View File

@ -32,7 +32,7 @@ public class TInteger extends TNumber implements TComparable<TInteger> {
}
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;
}
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.platform.PlatformAnnotationProvider;
/**
*
* @author Alexey Andreev
*/
public class AnnotationDependencyListener extends AbstractDependencyListener {
@Override
public void classReached(DependencyAgent agent, String className, CallLocation location) {

View File

@ -351,7 +351,7 @@ public class Decompiler {
graph = ProgramUtils.buildControlFlowGraph(program);
int[] weights = new int[graph.size()];
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()];
for (int i = 0; i < targetBlocks.length; ++i) {
@ -447,9 +447,7 @@ public class Decompiler {
if (node >= 0) {
generator.statements.clear();
TextLocation lastLocation = null;
List<Instruction> instructions = generator.currentBlock.getInstructions();
for (int j = 0; j < instructions.size(); ++j) {
Instruction insn = generator.currentBlock.getInstructions().get(j);
for (Instruction insn : generator.currentBlock) {
if (insn.getLocation() != null && 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.RegularMethodNode;
import org.teavm.common.Graph;
import org.teavm.model.BasicBlock;
import org.teavm.model.Instruction;
import org.teavm.model.Program;
import org.teavm.model.Variable;
@ -107,7 +108,7 @@ public class Optimizer {
Program originalProgram = splitter.getOriginalProgram();
Program program = splitter.getProgram(partIndex);
int[] successors = splitter.getBlockSuccessors(partIndex);
int[] splitPoints = splitter.getSplitPoints(partIndex);
Instruction[] splitPoints = splitter.getSplitPoints(partIndex);
int[] originalBlocks = splitter.getOriginalBlocks(partIndex);
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
DefinitionExtractor defExtractor = new DefinitionExtractor();
UsageExtractor useExtractor = new UsageExtractor();
List<Instruction> instructions = originalProgram.basicBlockAt(originalBlocks[i]).getInstructions();
int splitPoint = splitPoints[i];
for (int j = instructions.size() - 1; j >= splitPoint; --j) {
instructions.get(j).acceptVisitor(defExtractor);
instructions.get(j).acceptVisitor(useExtractor);
BasicBlock block = originalProgram.basicBlockAt(originalBlocks[i]);
Instruction splitPoint = splitPoints[i];
for (Instruction insn = block.getLastInstruction(); insn != splitPoint; insn = insn.getPrevious()) {
insn.acceptVisitor(defExtractor);
insn.acceptVisitor(useExtractor);
for (Variable var : defExtractor.getDefinedVariables()) {
liveVars.clear(var.getIndex());
}

View File

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

View File

@ -336,24 +336,24 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
ConstructInstruction newExceptionInsn = new ConstructInstruction();
newExceptionInsn.setType(NoSuchMethodError.class.getName());
newExceptionInsn.setReceiver(exceptionVar);
block.getInstructions().add(newExceptionInsn);
block.add(newExceptionInsn);
Variable constVar = program.createVariable();
StringConstantInstruction constInsn = new StringConstantInstruction();
constInsn.setConstant("Native method implementation not found: " + method.getReference());
constInsn.setReceiver(constVar);
block.getInstructions().add(constInsn);
block.add(constInsn);
InvokeInstruction initExceptionInsn = new InvokeInstruction();
initExceptionInsn.setInstance(exceptionVar);
initExceptionInsn.setMethod(new MethodReference(NoSuchMethodError.class, "<init>", String.class, void.class));
initExceptionInsn.setType(InvocationType.SPECIAL);
initExceptionInsn.getArguments().add(constVar);
block.getInstructions().add(initExceptionInsn);
block.add(initExceptionInsn);
RaiseInstruction raiseInsn = new RaiseInstruction();
raiseInsn.setException(exceptionVar);
block.getInstructions().add(raiseInsn);
block.add(raiseInsn);
controller.getDiagnostics().error(new CallLocation(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) {
for (int i = 0; i < block.getInstructions().size(); ++i) {
Instruction insn = block.getInstructions().get(i);
for (Instruction insn : block) {
if (insn instanceof InvokeInstruction) {
InvokeInstruction invoke = (InvokeInstruction) insn;
if (invoke.getType() != InvocationType.VIRTUAL) {
@ -49,7 +48,7 @@ public class NullPointerExceptionTransformer implements ClassHolderTransformer {
Variable var = block.getProgram().createVariable();
nullCheck.setReceiver(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);
InitClassInstruction initInsn = new InitClassInstruction();
initInsn.setClassName(method.getOwnerName());
entryBlock.getInstructions().add(0, initInsn);
entryBlock.addFirst(initInsn);
}
classInitializerEliminator.apply(program);
@ -689,7 +689,7 @@ public class WasmTarget implements TeaVMTarget {
}
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) {
for (Instruction insn : block) {
if (insn instanceof InvokeInstruction) {
InvokeInstruction invoke = (InvokeInstruction) insn;
if (invoke.getType() == InvocationType.VIRTUAL) {

View File

@ -45,8 +45,7 @@ public class ClassPatch implements ClassHolderTransformer {
private void patchProgram(Program program) {
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (int j = 0; j < block.getInstructions().size(); ++j) {
Instruction instruction = block.getInstructions().get(j);
for (Instruction instruction : block) {
if (instruction instanceof GetFieldInstruction) {
GetFieldInstruction getField = (GetFieldInstruction) instruction;
if (getField.getField().equals(platformClassField)) {
@ -54,14 +53,14 @@ public class ClassPatch implements ClassHolderTransformer {
replacement.setReceiver(getField.getReceiver());
replacement.setAssignee(getField.getInstance());
replacement.setLocation(instruction.getLocation());
block.getInstructions().set(j, replacement);
instruction.replace(replacement);
}
} else if (instruction instanceof PutFieldInstruction) {
PutFieldInstruction putField = (PutFieldInstruction) instruction;
if (putField.getField().equals(platformClassField)) {
EmptyInstruction replacement = new EmptyInstruction();
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.parsing.ClassDateProvider;
/**
*
* @author Alexey Andreev
*/
public class DiskProgramCache implements ProgramCache {
private File directory;
private ProgramIO programIO;
@ -86,7 +82,7 @@ public class DiskProgramCache implements ProgramCache {
Program program = cache.get(method).program;
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) {
for (Instruction insn : block) {
insn.acceptVisitor(analyzer);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,14 +18,16 @@ package org.teavm.model;
import java.util.*;
import org.teavm.model.instructions.InstructionReader;
public class BasicBlock implements BasicBlockReader {
public class BasicBlock implements BasicBlockReader, Iterable<Instruction> {
private Program program;
private int index;
private List<Phi> phis = new ArrayList<>();
private List<Instruction> instructions = new ArrayList<>();
private List<TryCatchBlock> tryCatchBlocks = new ArrayList<>();
private Variable exceptionVariable;
private String label;
Instruction firstInstruction;
Instruction lastInstruction;
int cachedSize;
BasicBlock(Program program, int index) {
this.program = program;
@ -50,59 +52,114 @@ public class BasicBlock implements BasicBlockReader {
this.program = null;
}
private List<Instruction> safeInstructions = new AbstractList<Instruction>() {
@Override
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 getFirstInstruction() {
return firstInstruction;
}
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>() {
@ -165,21 +222,52 @@ public class BasicBlock implements BasicBlockReader {
@Override
public int instructionCount() {
return instructions.size();
return cachedSize;
}
@Override
public void readInstruction(int index, InstructionReader reader) {
Instruction insn = instructions.get(index);
reader.location(insn.getLocation());
insn.acceptVisitor(new InstructionReadVisitor(reader));
public InstructionIterator iterateInstructions() {
return new InstructionIterator() {
Instruction instruction = firstInstruction;
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
public void readAllInstructions(InstructionReader reader) {
InstructionReadVisitor visitor = new InstructionReadVisitor(reader);
TextLocation location = null;
for (Instruction insn : instructions) {
for (Instruction insn : this) {
if (!Objects.equals(location, insn.getLocation())) {
location = insn.getLocation();
reader.location(location);

View File

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

View File

@ -15,15 +15,14 @@
*/
package org.teavm.model;
import java.util.Iterator;
import org.teavm.model.instructions.InstructionVisitor;
public abstract class Instruction {
private BasicBlock basicBlock;
BasicBlock basicBlock;
private TextLocation location;
void setBasicBlock(BasicBlock basicBlock) {
this.basicBlock = basicBlock;
}
Instruction next;
Instruction previous;
public BasicBlock getBasicBlock() {
return basicBlock;
@ -42,4 +41,127 @@ public abstract class Instruction {
}
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");
* you may not use this file except in compliance with the License.
@ -15,22 +15,16 @@
*/
package org.teavm.model;
import java.util.HashSet;
import java.util.Set;
import org.teavm.model.instructions.InstructionReader;
/**
*
* @author Alexey Andreev
*/
public class AsyncInformation {
private Set<MethodReference> syncMethods = new HashSet<>();
private Set<MethodReference> asyncMethods = new HashSet<>();
public interface InstructionIterator {
boolean hasNext();
public Set<MethodReference> getSyncMethods() {
return syncMethods;
}
void next();
public Set<MethodReference> getAsyncMethods() {
return asyncMethods;
}
boolean hasPrevious();
void previous();
void read(InstructionReader reader);
}

View File

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

View File

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

View File

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

View File

@ -60,7 +60,6 @@ class NullnessInformationBuilder {
private PhiUpdater phiUpdater;
private List<NullConstantInstruction> nullInstructions = new ArrayList<>();
private List<NullCheckInstruction> notNullInstructions = new ArrayList<>();
private List<List<Instruction>> additionalInstructionsByBlock = new ArrayList<>();
private Graph assignmentGraph;
private int[] nullPredecessorsLeft;
private int[] notNullPredecessorsLeft;
@ -90,14 +89,8 @@ class NullnessInformationBuilder {
}
private void insertAdditionalVariables() {
for (int i = 0; i < program.basicBlockCount(); ++i) {
additionalInstructionsByBlock.add(new ArrayList<>());
}
NullExtensionVisitor ev = new NullExtensionVisitor();
for (BasicBlock block : program.getBasicBlocks()) {
ev.currentBasicBlock = block;
Instruction lastInstruction = block.getLastInstruction();
if (lastInstruction instanceof BranchingInstruction) {
BranchingInstruction branching = (BranchingInstruction) lastInstruction;
@ -108,17 +101,12 @@ class NullnessInformationBuilder {
}
}
for (ev.index = 0; ev.index < block.getInstructions().size(); ++ev.index) {
Instruction instruction = block.getInstructions().get(ev.index);
for (Instruction instruction = block.getFirstInstruction(); instruction != null;) {
Instruction next = instruction.getNext();
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() {
@ -139,12 +127,12 @@ class NullnessInformationBuilder {
NullCheckInstruction notNullInstruction = new NullCheckInstruction();
notNullInstruction.setValue(variable);
notNullInstruction.setReceiver(variable);
additionalInstructionsByBlock.get(notNullBlock.getIndex()).add(notNullInstruction);
notNullBlock.addFirst(notNullInstruction);
notNullInstructions.add(notNullInstruction);
NullConstantInstruction nullInstruction = new NullConstantInstruction();
nullInstruction.setReceiver(variable);
additionalInstructionsByBlock.get(nullBlock.getIndex()).add(nullInstruction);
nullBlock.addFirst(nullInstruction);
nullInstructions.add(nullInstruction);
}
@ -164,7 +152,7 @@ class NullnessInformationBuilder {
}
}
for (Instruction instruction : block.getInstructions()) {
for (Instruction instruction : block) {
if (instruction instanceof AssignInstruction) {
AssignInstruction assignment = (AssignInstruction) instruction;
builder.addEdge(assignment.getAssignee().getIndex(), assignment.getReceiver().getIndex());
@ -185,68 +173,65 @@ class NullnessInformationBuilder {
private void findKnownNullness() {
for (BasicBlock block : program.getBasicBlocks()) {
for (Instruction instruction : block.getInstructions()) {
for (Instruction instruction : block) {
instruction.acceptVisitor(nullnessVisitor);
}
}
}
class NullExtensionVisitor extends AbstractInstructionVisitor {
int index;
BasicBlock currentBasicBlock;
@Override
public void visit(GetFieldInstruction insn) {
if (insn.getInstance() != null) {
insertNotNullInstruction(insn.getInstance());
insertNotNullInstruction(insn, insn.getInstance());
}
}
@Override
public void visit(PutFieldInstruction insn) {
if (insn.getInstance() != null) {
insertNotNullInstruction(insn.getInstance());
insertNotNullInstruction(insn, insn.getInstance());
}
}
@Override
public void visit(ArrayLengthInstruction insn) {
insertNotNullInstruction(insn.getArray());
insertNotNullInstruction(insn, insn.getArray());
}
@Override
public void visit(CloneArrayInstruction insn) {
insertNotNullInstruction(insn.getArray());
insertNotNullInstruction(insn, insn.getArray());
}
@Override
public void visit(UnwrapArrayInstruction insn) {
insertNotNullInstruction(insn.getArray());
insertNotNullInstruction(insn, insn.getArray());
}
@Override
public void visit(InvokeInstruction insn) {
if (insn.getInstance() != null) {
insertNotNullInstruction(insn.getInstance());
insertNotNullInstruction(insn, insn.getInstance());
}
}
@Override
public void visit(MonitorEnterInstruction insn) {
insertNotNullInstruction(insn.getObjectRef());
insertNotNullInstruction(insn, insn.getObjectRef());
}
@Override
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();
insn.setReceiver(var);
insn.setValue(var);
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.util.InstructionTransitionExtractor;
/**
*
* @author Alexey Andreev
*/
public final class ProgramEmitter {
private Program program;
private BasicBlock block;
@ -388,7 +384,7 @@ public final class ProgramEmitter {
if (currentLocation != null) {
insn.setLocation(currentLocation);
}
block.getInstructions().add(insn);
block.add(insn);
}
public static ProgramEmitter create(MethodHolder method, ClassReaderSource classSource) {
@ -404,7 +400,7 @@ public final class ProgramEmitter {
JumpInstruction insn = new JumpInstruction();
insn.setTarget(block);
zeroBlock.getInstructions().add(insn);
zeroBlock.add(insn);
program.createVariable();
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.SwitchTableEntry;
/**
*
* @author Alexey Andreev
*/
public class StringChooseEmitter {
private ProgramEmitter pe;
private ValueEmitter testValue;
@ -78,7 +74,7 @@ public class StringChooseEmitter {
}
public ProgramEmitter otherwise(FragmentEmitter fragment) {
otherwiseBlock.getInstructions().clear();
otherwiseBlock.removeAllInstructions();
pe.enter(otherwiseBlock);
pe.emitAndJump(fragment, joinBlock);
pe.enter(joinBlock);

View File

@ -18,10 +18,6 @@ package org.teavm.model.instructions;
import org.teavm.model.Instruction;
import org.teavm.model.Variable;
/**
*
* @author Alexey Andreev
*/
public class ArrayLengthInstruction extends Instruction {
private Variable array;
private Variable receiver;

View File

@ -17,10 +17,6 @@ package org.teavm.model.instructions;
import org.teavm.model.Instruction;
/**
*
* @author Alexey Andreev
*/
public class EmptyInstruction extends Instruction {
@Override
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.Instruction;
/**
*
* @author Alexey Andreev
*/
public class JumpInstruction extends Instruction {
private BasicBlock target;

View File

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

View File

@ -15,8 +15,6 @@
*/
package org.teavm.model.lowlevel;
import java.util.ArrayList;
import java.util.List;
import org.teavm.model.BasicBlock;
import org.teavm.model.Incoming;
import org.teavm.model.Instruction;
@ -44,33 +42,31 @@ public class ClassInitializerTransformer {
for (int i = 0; i < basicBlockMap.length; ++i) {
BasicBlock block = program.basicBlockAt(i);
List<Instruction> instructions = block.getInstructions();
for (int j = 0; j < instructions.size(); ++j) {
Instruction instruction = instructions.get(j);
if (instruction instanceof InitClassInstruction) {
String className = ((InitClassInstruction) instruction).getClassName();
BasicBlock continueBlock = program.createBasicBlock();
List<Instruction> instructionsToMove = instructions.subList(j + 1, instructions.size());
List<Instruction> instructionsToMoveCopy = new ArrayList<>(instructionsToMove);
instructionsToMove.clear();
continueBlock.getInstructions().addAll(instructionsToMoveCopy);
continueBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
BasicBlock initBlock = program.createBasicBlock();
instructions.remove(j);
initBlock.getInstructions().add(instruction);
JumpInstruction jumpToContinue = new JumpInstruction();
jumpToContinue.setTarget(continueBlock);
initBlock.getInstructions().add(jumpToContinue);
createInitCheck(program, block, className, continueBlock, initBlock);
basicBlockMap[i] = continueBlock.getIndex();
block = continueBlock;
instructions = block.getInstructions();
j = 0;
for (Instruction instruction : block) {
if (!(instruction instanceof InitClassInstruction)) {
continue;
}
String className = ((InitClassInstruction) instruction).getClassName();
block = instruction.getBasicBlock();
BasicBlock continueBlock = program.createBasicBlock();
while (instruction.getNext() != null) {
Instruction toMove = instruction.getNext();
toMove.delete();
continueBlock.add(toMove);
}
continueBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
BasicBlock initBlock = program.createBasicBlock();
instruction.delete();
initBlock.add(instruction);
JumpInstruction jumpToContinue = new JumpInstruction();
jumpToContinue.setTarget(continueBlock);
initBlock.add(jumpToContinue);
createInitCheck(program, block, className, continueBlock, initBlock);
basicBlockMap[i] = continueBlock.getIndex();
}
}
@ -94,19 +90,19 @@ public class ClassInitializerTransformer {
ClassConstantInstruction clsConstant = new ClassConstantInstruction();
clsConstant.setReceiver(clsVariable);
clsConstant.setConstant(ValueType.object(className));
block.getInstructions().add(clsConstant);
block.add(clsConstant);
InvokeInstruction checkInitialized = new InvokeInstruction();
checkInitialized.setType(InvocationType.SPECIAL);
checkInitialized.setMethod(new MethodReference(Allocator.class, "isInitialized", Class.class, boolean.class));
checkInitialized.getArguments().add(clsVariable);
checkInitialized.setReceiver(initializedVariable);
block.getInstructions().add(checkInitialized);
block.add(checkInitialized);
BranchingInstruction branching = new BranchingInstruction(BranchingCondition.EQUAL);
branching.setOperand(initializedVariable);
branching.setConsequent(continueBlock);
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",
Throwable.class));
catchCall.setReceiver(block.getExceptionVariable());
block.getInstructions().add(0, catchCall);
block.addFirst(catchCall);
block.setExceptionVariable(null);
}
@ -123,8 +123,6 @@ public class ExceptionHandlingShadowStackContributor {
}
private int contributeToBasicBlock(BasicBlock block) {
List<Instruction> instructions = block.getInstructions();
int[] currentJointSources = new int[program.variableCount()];
int[] jointReceiverMap = new int[program.variableCount()];
Arrays.fill(currentJointSources, -1);
@ -147,9 +145,7 @@ public class ExceptionHandlingShadowStackContributor {
List<BasicBlock> blocksToClearHandlers = new ArrayList<>();
blocksToClearHandlers.add(block);
for (int i = 0; i < instructions.size(); ++i) {
Instruction insn = instructions.get(i);
for (Instruction insn : block) {
if (isCallInstruction(insn)) {
BasicBlock next;
boolean last = false;
@ -160,21 +156,23 @@ public class ExceptionHandlingShadowStackContributor {
raise.setType(InvocationType.SPECIAL);
raise.getArguments().add(((RaiseInstruction) insn).getException());
raise.setLocation(insn.getLocation());
instructions.set(i, raise);
insn.replace(raise);
insn = raise;
next = null;
} else if (i < instructions.size() - 1 && instructions.get(i + 1) instanceof JumpInstruction) {
next = ((JumpInstruction) instructions.get(i + 1)).getTarget();
instructions.remove(i + 1);
} else if (insn.getNext() != null && insn.getNext() instanceof JumpInstruction) {
next = ((JumpInstruction) insn.getNext()).getTarget();
insn.getNext().delete();
last = true;
} else {
next = program.createBasicBlock();
next.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
blocksToClearHandlers.add(next);
List<Instruction> remainingInstructions = instructions.subList(i + 1, instructions.size());
List<Instruction> instructionsToMove = new ArrayList<>(remainingInstructions);
remainingInstructions.clear();
next.getInstructions().addAll(instructionsToMove);
while (insn.getNext() != null) {
Instruction nextInsn = insn.getNext();
nextInsn.delete();
next.add(nextInsn);
}
}
CallSiteDescriptor callSite = new CallSiteDescriptor(callSites.size());
@ -182,16 +180,14 @@ public class ExceptionHandlingShadowStackContributor {
List<Instruction> pre = setLocation(getInstructionsBeforeCallSite(callSite), insn.getLocation());
List<Instruction> post = getInstructionsAfterCallSite(block, next, callSite, currentJointSources);
post = setLocation(post, insn.getLocation());
instructions.addAll(instructions.size() - 1, pre);
instructions.addAll(post);
insn.insertPreviousAll(pre);
insn.insertNextAll(post);
hasExceptionHandlers = true;
if (next == null || last) {
break;
}
block = next;
instructions = block.getInstructions();
i = -1;
}
insn.acceptVisitor(defExtractor);
@ -323,10 +319,10 @@ public class ExceptionHandlingShadowStackContributor {
private BasicBlock getDefaultExceptionHandler() {
if (defaultExceptionHandler == null) {
defaultExceptionHandler = program.createBasicBlock();
Variable result = createReturnValueInstructions(defaultExceptionHandler.getInstructions());
Variable result = createReturnValueInstructions(defaultExceptionHandler);
ExitInstruction exit = new ExitInstruction();
exit.setValueToReturn(result);
defaultExceptionHandler.getInstructions().add(exit);
defaultExceptionHandler.add(exit);
}
return defaultExceptionHandler;
}
@ -343,7 +339,7 @@ public class ExceptionHandlingShadowStackContributor {
return phi;
}
private Variable createReturnValueInstructions(List<Instruction> instructions) {
private Variable createReturnValueInstructions(BasicBlock block) {
ValueType returnType = method.getReturnType();
if (returnType == ValueType.VOID) {
return null;
@ -360,29 +356,29 @@ public class ExceptionHandlingShadowStackContributor {
case INTEGER:
IntegerConstantInstruction intConstant = new IntegerConstantInstruction();
intConstant.setReceiver(variable);
instructions.add(intConstant);
block.add(intConstant);
return variable;
case LONG:
LongConstantInstruction longConstant = new LongConstantInstruction();
longConstant.setReceiver(variable);
instructions.add(longConstant);
block.add(longConstant);
return variable;
case FLOAT:
FloatConstantInstruction floatConstant = new FloatConstantInstruction();
floatConstant.setReceiver(variable);
instructions.add(floatConstant);
block.add(floatConstant);
return variable;
case DOUBLE:
DoubleConstantInstruction doubleConstant = new DoubleConstantInstruction();
doubleConstant.setReceiver(variable);
instructions.add(doubleConstant);
block.add(doubleConstant);
return variable;
}
}
NullConstantInstruction nullConstant = new NullConstantInstruction();
nullConstant.setReceiver(variable);
instructions.add(nullConstant);
block.add(nullConstant);
return variable;
}

View File

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

View File

@ -78,7 +78,7 @@ public class ShadowStackTransformer {
invocation.getArguments().add(sizeVariable);
instructionsToAdd.add(invocation);
block.getInstructions().addAll(0, instructionsToAdd);
block.addFirstAll(instructionsToAdd);
}
private void addStackRelease(Program program, int maxDepth) {
@ -101,7 +101,7 @@ public class ShadowStackTransformer {
} else {
exitBlock = program.createBasicBlock();
ExitInstruction exit = new ExitInstruction();
exitBlock.getInstructions().add(exit);
exitBlock.add(exit);
if (hasResult) {
Phi phi = new Phi();
@ -125,7 +125,7 @@ public class ShadowStackTransformer {
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);
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;
import java.util.ArrayList;
import java.util.List;
import org.teavm.model.*;
import org.teavm.model.instructions.EmptyInstruction;
import org.teavm.model.BasicBlock;
import org.teavm.model.Instruction;
import org.teavm.model.Program;
import org.teavm.model.Variable;
import org.teavm.model.instructions.UnwrapArrayInstruction;
import org.teavm.model.util.DefinitionExtractor;
@ -32,42 +32,32 @@ public class ArrayUnwrapMotion implements MethodOptimization {
}
private void optimize(BasicBlock block) {
List<Instruction> newInstructions = new ArrayList<>();
List<Instruction> instructions = block.getInstructions();
for (int i = 0; i < instructions.size(); ++i) {
Instruction insn = instructions.get(i);
for (Instruction insn : block) {
if (insn instanceof UnwrapArrayInstruction) {
UnwrapArrayInstruction unwrap = (UnwrapArrayInstruction) insn;
EmptyInstruction empty = new EmptyInstruction();
empty.setLocation(unwrap.getLocation());
instructions.set(i, empty);
int def = whereDefined(instructions, i, unwrap.getArray());
if (def < 0) {
newInstructions.add(unwrap);
Instruction def = whereDefined(insn, unwrap.getArray());
insn.delete();
if (def == null) {
block.addFirst(unwrap);
} else {
instructions.add(def + 1, unwrap);
unwrap.setLocation(instructions.get(def).getLocation());
++i;
def.insertNext(unwrap);
unwrap.setLocation(def.getLocation());
}
}
}
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();
while (index >= 0) {
Instruction insn = instructions.get(index);
insn.acceptVisitor(def);
while (instruction != null) {
instruction.acceptVisitor(def);
for (Variable defVar : def.getDefinedVariables()) {
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.Deque;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.teavm.common.DominatorTree;
import org.teavm.common.Graph;
@ -26,7 +25,6 @@ import org.teavm.common.GraphUtils;
import org.teavm.model.BasicBlock;
import org.teavm.model.Instruction;
import org.teavm.model.Program;
import org.teavm.model.instructions.EmptyInstruction;
import org.teavm.model.instructions.InitClassInstruction;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.util.ProgramUtils;
@ -47,16 +45,14 @@ public class ClassInitElimination implements MethodOptimization {
Step step = stack.pop();
int node = step.node;
BasicBlock block = program.basicBlockAt(node);
List<Instruction> instructions = block.getInstructions();
for (int i = 0; i < instructions.size(); ++i) {
Instruction insn = instructions.get(i);
Instruction nextInsn;
for (Instruction insn = block.getFirstInstruction(); insn != null; insn = nextInsn) {
nextInsn = insn.getNext();
if (insn instanceof InitClassInstruction) {
InitClassInstruction initClass = (InitClassInstruction) insn;
if (!step.initializedClasses.add(initClass.getClassName())) {
EmptyInstruction empty = new EmptyInstruction();
empty.setLocation(initClass.getLocation());
instructions.set(i, empty);
insn.delete();
}
continue;
}

View File

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

View File

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

View File

@ -31,7 +31,7 @@ public class EmptyBlockElimination implements MethodOptimization {
int lastNonEmpty = program.basicBlockCount() - 1;
for (int i = program.basicBlockCount() - 2; i > 0; --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) {
JumpInstruction insn = (JumpInstruction) block.getLastInstruction();
if (insn.getTarget().getIndex() == i + 1) {
@ -40,7 +40,7 @@ public class EmptyBlockElimination implements MethodOptimization {
}
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) {
if (blockMapping[i] != i) {
program.deleteBasicBlock(i);

View File

@ -81,15 +81,14 @@ public class GlobalValueNumbering implements MethodOptimization {
block.setExceptionVariable(program.variableAt(var));
}
for (int i = 0; i < block.getInstructions().size(); ++i) {
for (Instruction currentInsn : block) {
evaluatedConstant = null;
Instruction currentInsn = block.getInstructions().get(i);
currentInsn.acceptVisitor(optimizer);
if (eliminate) {
affected = true;
EmptyInstruction empty = new EmptyInstruction();
empty.setLocation(currentInsn.getLocation());
block.getInstructions().set(i, empty);
currentInsn.replace(empty);
eliminate = false;
} else if (evaluatedConstant != null) {
if (evaluatedConstant instanceof Integer) {
@ -97,25 +96,25 @@ public class GlobalValueNumbering implements MethodOptimization {
newInsn.setConstant((Integer) evaluatedConstant);
newInsn.setReceiver(program.variableAt(receiver));
newInsn.setLocation(currentInsn.getLocation());
block.getInstructions().set(i, newInsn);
currentInsn.replace(newInsn);
} else if (evaluatedConstant instanceof Long) {
LongConstantInstruction newInsn = new LongConstantInstruction();
newInsn.setConstant((Long) evaluatedConstant);
newInsn.setReceiver(program.variableAt(receiver));
newInsn.setLocation(currentInsn.getLocation());
block.getInstructions().set(i, newInsn);
currentInsn.replace(newInsn);
} else if (evaluatedConstant instanceof Float) {
FloatConstantInstruction newInsn = new FloatConstantInstruction();
newInsn.setConstant((Float) evaluatedConstant);
newInsn.setReceiver(program.variableAt(receiver));
newInsn.setLocation(currentInsn.getLocation());
block.getInstructions().set(i, newInsn);
currentInsn.replace(newInsn);
} else if (evaluatedConstant instanceof Double) {
DoubleConstantInstruction newInsn = new DoubleConstantInstruction();
newInsn.setConstant((Double) evaluatedConstant);
newInsn.setReceiver(program.variableAt(receiver));
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.Phi;
import org.teavm.model.Program;
import org.teavm.model.TryCatchBlock;
import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BranchingInstruction;
@ -62,7 +63,7 @@ public class Inlining {
private void execPlanEntry(Program program, PlanEntry planEntry, int 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 firstInlineBlock = program.createBasicBlock();
Program inlineProgram = planEntry.program;
@ -75,30 +76,43 @@ public class Inlining {
program.createVariable();
}
List<Instruction> movedInstructions = block.getInstructions().subList(planEntry.targetInstruction + 1,
block.getInstructions().size());
List<Instruction> instructionsToMove = new ArrayList<>(movedInstructions);
movedInstructions.clear();
splitBlock.getInstructions().addAll(instructionsToMove);
while (planEntry.targetInstruction.getNext() != null) {
Instruction insn = planEntry.targetInstruction.getNext();
insn.delete();
splitBlock.add(insn);
}
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>")) {
InitClassInstruction clinit = new InitClassInstruction();
clinit.setClassName(invoke.getMethod().getClassName());
block.getInstructions().add(clinit);
block.add(clinit);
}
JumpInstruction jumpToInlinedProgram = new JumpInstruction();
jumpToInlinedProgram.setTarget(firstInlineBlock);
block.getInstructions().add(jumpToInlinedProgram);
block.add(jumpToInlinedProgram);
for (int i = 0; i < inlineProgram.basicBlockCount(); ++i) {
BasicBlock blockToInline = inlineProgram.basicBlockAt(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);
}
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(index -> index + firstInlineBlock.getIndex());
BasicBlockMapper blockMapper = new BasicBlockMapper((BasicBlock b) ->
program.basicBlockAt(b.getIndex() + firstInlineBlock.getIndex()));
InstructionVariableMapper variableMapper = new InstructionVariableMapper(var -> {
if (var.getIndex() == 0) {
return invoke.getInstance();
@ -120,7 +134,7 @@ public class Inlining {
ExitInstruction exit = (ExitInstruction) lastInsn;
JumpInstruction exitReplacement = new JumpInstruction();
exitReplacement.setTarget(splitBlock);
mappedBlock.getInstructions().set(mappedBlock.getInstructions().size() - 1, exitReplacement);
exit.replace(exitReplacement);
if (exit.getValueToReturn() != null) {
Incoming resultIncoming = new Incoming();
resultIncoming.setSource(mappedBlock);
@ -135,7 +149,7 @@ public class Inlining {
AssignInstruction resultAssignment = new AssignInstruction();
resultAssignment.setReceiver(invoke.getReceiver());
resultAssignment.setAssignee(resultVariables.get(0).getValue());
splitBlock.getInstructions().add(0, resultAssignment);
splitBlock.addFirst(resultAssignment);
} else {
Phi resultPhi = new Phi();
resultPhi.setReceiver(invoke.getReceiver());
@ -170,14 +184,11 @@ public class Inlining {
List<PlanEntry> plan = new ArrayList<>();
int ownComplexity = getComplexity(program);
for (int i = program.basicBlockCount() - 1; i >= 0; --i) {
BasicBlock block = program.basicBlockAt(i);
for (BasicBlock block : program.getBasicBlocks()) {
if (!block.getTryCatchBlocks().isEmpty()) {
continue;
}
List<Instruction> instructions = block.getInstructions();
for (int j = instructions.size() - 1; j >= 0; --j) {
Instruction insn = instructions.get(j);
for (Instruction insn : block) {
if (!(insn instanceof InvokeInstruction)) {
continue;
}
@ -202,13 +213,14 @@ public class Inlining {
}
PlanEntry entry = new PlanEntry();
entry.targetBlock = i;
entry.targetInstruction = j;
entry.targetBlock = block.getIndex();
entry.targetInstruction = insn;
entry.program = invokedProgram;
entry.innerPlan.addAll(buildPlan(invokedProgram, classSource, depth + 1));
plan.add(entry);
}
}
Collections.reverse(plan);
return plan;
}
@ -222,20 +234,20 @@ public class Inlining {
int complexity = 0;
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
List<Instruction> instructions = block.getInstructions();
int nopCount = (int) instructions.stream().filter(insn -> insn instanceof EmptyInstruction).count();
int invokeCount = instructions.stream().mapToInt(insn -> {
if (!(insn instanceof InvokeInstruction)) {
return 0;
int nopCount = 0;
int invokeCount = 0;
for (Instruction insn : block) {
if (insn instanceof EmptyInstruction) {
nopCount++;
} else if (insn instanceof InvokeInstruction) {
InvokeInstruction invoke = (InvokeInstruction) insn;
invokeCount += invoke.getArguments().size();
if (invoke.getInstance() != null) {
invokeCount++;
}
}
InvokeInstruction invoke = (InvokeInstruction) insn;
int count = invoke.getArguments().size();
if (invoke.getInstance() != null) {
count++;
}
return count + 1;
}).sum();
complexity += instructions.size() - 1 - nopCount + invokeCount;
}
complexity += block.instructionCount() - nopCount + invokeCount;
Instruction lastInsn = block.getLastInstruction();
if (lastInsn instanceof SwitchInstruction) {
complexity += 3;
@ -248,7 +260,7 @@ public class Inlining {
private class PlanEntry {
int targetBlock;
int targetInstruction;
Instruction targetInstruction;
Program program;
final List<PlanEntry> innerPlan = new ArrayList<>();
}

View File

@ -65,8 +65,9 @@ public class LoopInvariantMotion implements MethodOptimization {
boolean dominatesExits = exits != null && Arrays.stream(exits)
.allMatch(exit -> dom.dominates(v, exit));
BasicBlock block = program.basicBlockAt(v);
insnLoop: for (int i = 0; i < block.getInstructions().size(); ++i) {
Instruction insn = block.getInstructions().get(i);
Instruction nextInsn;
insnLoop: for (Instruction insn = block.getFirstInstruction(); insn != null; insn = nextInsn) {
nextInsn = insn.getNext();
insn.acceptVisitor(defExtractor);
Variable[] defs = defExtractor.getDefinedVariables();
for (Variable def : defs) {
@ -113,9 +114,8 @@ public class LoopInvariantMotion implements MethodOptimization {
EmptyInstruction empty = new EmptyInstruction();
empty.setLocation(insn.getLocation());
block.getInstructions().set(i, empty);
int preheader = getPreheader(defLoop.getHead());
List<Instruction> preheaderInstructions = program.basicBlockAt(preheader).getInstructions();
insn.replace(empty);
BasicBlock preheader = program.basicBlockAt(getPreheader(defLoop.getHead()));
List<Instruction> newInstructions = new ArrayList<>();
Variable[] variableMap = null;
for (Variable use : useExtractor.getUsedVariables()) {
@ -137,7 +137,7 @@ public class LoopInvariantMotion implements MethodOptimization {
insn.acceptVisitor(new InstructionVariableMapper(var -> currentVariableMap[var.getIndex()]));
}
newInstructions.add(insn);
preheaderInstructions.addAll(preheaderInstructions.size() - 1, newInstructions);
preheader.getLastInstruction().insertPreviousAll(newInstructions);
defLocation[defs[0].getIndex()] = commonUseLoop != null ? commonUseLoop.getHead() : 0;
affected = true;
}
@ -180,7 +180,7 @@ public class LoopInvariantMotion implements MethodOptimization {
JumpInstruction escapeInsn = new JumpInstruction();
BasicBlock header = program.basicBlockAt(headerIndex);
escapeInsn.setTarget(header);
preheader.getInstructions().add(escapeInsn);
preheader.add(escapeInsn);
for (Phi phi : header.getPhis()) {
Phi preheaderPhi = null;
@ -208,7 +208,7 @@ public class LoopInvariantMotion implements MethodOptimization {
if (!dom.dominates(headerIndex, predIndex)) {
BasicBlock pred = program.basicBlockAt(predIndex);
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);
Set<Variable> currentInvariants = new HashSet<>();
for (Instruction insn : block.getInstructions()) {
for (Instruction insn : block) {
invariantAnalyzer.reset();
insn.acceptVisitor(invariantAnalyzer);
if (!invariantAnalyzer.canMove && !invariantAnalyzer.constant) {
@ -304,7 +304,7 @@ class LoopInversionImpl {
}
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);
for (int node : copiedNodes.keys().toArray()) {
@ -314,11 +314,11 @@ class LoopInversionImpl {
targetBlock.setExceptionVariable(sourceBlock.getExceptionVariable());
copier.resetLocation();
for (int i = 0; i < sourceBlock.instructionCount(); ++i) {
sourceBlock.readInstruction(i, copier);
Instruction insn = copier.getCopy();
List<Instruction> instructionCopies = ProgramUtils.copyInstructions(sourceBlock.getFirstInstruction(),
null, targetBlock.getProgram());
for (Instruction insn : instructionCopies) {
insn.acceptVisitor(blockMapper);
targetBlock.getInstructions().add(insn);
targetBlock.add(insn);
}
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.
*/
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()) {
BasicBlock block = program.basicBlockAt(node);

View File

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

View File

@ -65,11 +65,11 @@ public class UnusedVariableElimination implements MethodOptimization {
block.setExceptionVariable(null);
}
for (int j = 0; j < block.getInstructions().size(); ++j) {
for (Instruction insn : block) {
insnOptimizer.eliminate = false;
block.getInstructions().get(j).acceptVisitor(insnOptimizer);
insn.acceptVisitor(insnOptimizer);
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.instructions.*;
/**
*
* @author Alexey Andreev
*/
public final class VariableEscapeAnalyzer {
private VariableEscapeAnalyzer() {
}
@ -31,7 +27,7 @@ public final class VariableEscapeAnalyzer {
InstructionAnalyzer analyzer = new InstructionAnalyzer(escaping);
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) {
for (Instruction insn : block) {
insn.acceptVisitor(analyzer);
}
}

View File

@ -29,7 +29,7 @@ public final class VariableUsageGraphBuilder {
InstructionAnalyzer analyzer = new InstructionAnalyzer(builder);
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) {
for (Instruction insn : block) {
insn.acceptVisitor(analyzer);
}
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) {
sb.append("@").append(receiver.getIndex()).append(" := field ");
escapeIdentifierIfNeeded(field.toString(), sb);
sb.append(field);
if (instance != null) {
sb.append(" @").append(instance.getIndex());
}
@ -407,13 +406,15 @@ class InstructionStringifier implements InstructionReader {
escapeIdentifierIfNeeded(method.toString(), sb);
if (instance != null) {
sb.append(' ');
sb.append("@").append(instance.getIndex());
}
for (int i = 0; i < arguments.size(); ++i) {
if (instance != null || i > 0) {
sb.append(", ");
sb.append(",");
}
sb.append(' ');
sb.append("@").append(arguments.get(i).getIndex());
}
}

View File

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

View File

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

View File

@ -15,20 +15,24 @@
*/
package org.teavm.model.util;
import java.util.function.Function;
import java.util.function.IntUnaryOperator;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
public class BasicBlockMapper implements InstructionVisitor {
private IntUnaryOperator mapFunction;
public class BasicBlockMapper extends AbstractInstructionVisitor {
private Function<BasicBlock, BasicBlock> mapFunction;
public BasicBlockMapper(IntUnaryOperator mapFunction) {
public BasicBlockMapper(Function<BasicBlock, BasicBlock> mapFunction) {
this.mapFunction = mapFunction;
}
public BasicBlockMapper(IntUnaryOperator mapFunction) {
this((BasicBlock block) -> block.getProgram().basicBlockAt(mapFunction.applyAsInt(block.getIndex())));
}
private BasicBlock map(BasicBlock block) {
Program program = block.getProgram();
return program.basicBlockAt(mapFunction.applyAsInt(block.getIndex()));
return mapFunction.apply(block);
}
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
public void visit(BranchingInstruction insn) {
insn.setConsequent(map(insn.getConsequent()));
@ -134,80 +82,4 @@ public class BasicBlockMapper implements InstructionVisitor {
}
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) {
for (Instruction insn : block.getInstructions()) {
for (Instruction insn : block) {
insn.acceptVisitor(this);
}
}

View File

@ -61,8 +61,7 @@ class InterferenceGraphBuilder {
}
}
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(useExtractor);
insn.acceptVisitor(defExtractor);
for (Variable var : defExtractor.getDefinedVariables()) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -36,12 +36,11 @@ public class ProgramNodeSplittingBackend implements GraphSplittingBackend {
int node = nodes[i];
BasicBlock block = program.basicBlockAt(node);
BasicBlock blockCopy = program.createBasicBlock();
blockCopy.getInstructions().addAll(ProgramUtils.copyInstructions(block, 0,
block.getInstructions().size(), program));
blockCopy.addAll(ProgramUtils.copyInstructions(block.getFirstInstruction(), null, program));
copies[i] = blockCopy.getIndex();
map.put(nodes[i], copies[i] + 1);
}
BasicBlockMapper copyBlockMapper = new BasicBlockMapper(block -> {
BasicBlockMapper copyBlockMapper = new BasicBlockMapper((int block) -> {
int mappedIndex = map.get(block);
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.IncomingReader;
import org.teavm.model.Instruction;
import org.teavm.model.InstructionIterator;
import org.teavm.model.InstructionReadVisitor;
import org.teavm.model.Phi;
import org.teavm.model.PhiReader;
import org.teavm.model.Program;
@ -89,17 +91,24 @@ public final class ProgramUtils {
if (block.getExceptionVariable() != null) {
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.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<>();
InstructionCopyReader copyReader = new InstructionCopyReader(target);
for (int i = from; i < to; ++i) {
block.readInstruction(i, copyReader);
InstructionReadVisitor visitor = new InstructionReadVisitor(copyReader);
while (from != to) {
from.acceptVisitor(visitor);
result.add(copyReader.getCopy());
from = from.getNext();
}
return result;
}
@ -195,7 +204,7 @@ public final class ProgramUtils {
places[phi.getReceiver().getIndex()] = block;
}
for (Instruction insn : block.getInstructions()) {
for (Instruction insn : block) {
insn.acceptVisitor(defExtractor);
for (Variable var : defExtractor.getDefinedVariables()) {
places[var.getIndex()] = block;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,9 +16,6 @@
package org.teavm.model.text;
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.InputStream;
import java.io.InputStreamReader;
@ -26,20 +23,6 @@ import org.junit.Assert;
import org.junit.Test;
import org.teavm.model.BasicBlock;
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 {
@Test
@ -47,8 +30,8 @@ public class ParserTest {
Program program = runTest("simple");
assertEquals(2, program.basicBlockCount());
assertEquals(4, program.variableCount());
assertEquals(4, program.basicBlockAt(0).getInstructions().size());
assertEquals(1, program.basicBlockAt(1).getInstructions().size());
assertEquals(4, program.basicBlockAt(0).instructionCount());
assertEquals(1, program.basicBlockAt(1).instructionCount());
}
@Test
@ -56,7 +39,7 @@ public class ParserTest {
Program program = runTest("conditional");
assertEquals(7, program.basicBlockCount());
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());
BasicBlock block = program.basicBlockAt(0);
assertEquals(7, block.getInstructions().size());
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);
assertEquals(7, block.instructionCount());
}
@Test
public void invocation() throws Exception {
Program program = runTest("invocation");
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
public void casting() throws Exception {
Program program = runTest("casting");
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
@ -129,11 +80,6 @@ public class ParserTest {
public void create() throws Exception {
Program program = runTest("create");
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

View File

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

View File

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

View File

@ -197,13 +197,14 @@ public class CompositeMethodGenerator {
templateBlock.readAllInstructions(substitutor);
// 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);
for (int j = 0; j < blockOutgoings.size(); ++j) {
VariableReader outgoingVar = outgoingVars.get(i).get(j);
blockOutgoings.get(j).setValue(substitutor.var(outgoingVar));
}
targetBlock.getInstructions().add(lastInsn);
targetBlock.add(lastInsn);
phiBlockMap.put(targetBlock, currentBlock());
}
@ -235,7 +236,7 @@ public class CompositeMethodGenerator {
void add(Instruction insn) {
insn.setLocation(forcedLocation != null ? forcedLocation : location);
program.basicBlockAt(blockIndex).getInstructions().add(insn);
program.basicBlockAt(blockIndex).add(insn);
}
Variable captureValue(CapturedValue captured) {

View File

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

View File

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

View File

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

View File

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