mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Store instructions as double-linked list instead of ArrayList
This commit is contained in:
parent
231dcbaf36
commit
ae5e1e4962
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<>();
|
||||
|
||||
|
|
|
@ -15,10 +15,6 @@
|
|||
*/
|
||||
package org.teavm.model;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface AnnotationContainerReader {
|
||||
AnnotationReader get(String type);
|
||||
|
||||
|
|
|
@ -15,10 +15,6 @@
|
|||
*/
|
||||
package org.teavm.model;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface AnnotationReader {
|
||||
String getType();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -27,7 +27,7 @@ public interface BasicBlockReader {
|
|||
|
||||
int instructionCount();
|
||||
|
||||
void readInstruction(int index, InstructionReader reader);
|
||||
InstructionIterator iterateInstructions();
|
||||
|
||||
void readAllInstructions(InstructionReader reader);
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
for (Instruction instruction : block) {
|
||||
if (!(instruction instanceof InitClassInstruction)) {
|
||||
continue;
|
||||
}
|
||||
String className = ((InitClassInstruction) instruction).getClassName();
|
||||
block = instruction.getBasicBlock();
|
||||
|
||||
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);
|
||||
while (instruction.getNext() != null) {
|
||||
Instruction toMove = instruction.getNext();
|
||||
toMove.delete();
|
||||
continueBlock.add(toMove);
|
||||
}
|
||||
continueBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
|
||||
|
||||
BasicBlock initBlock = program.createBasicBlock();
|
||||
instructions.remove(j);
|
||||
initBlock.getInstructions().add(instruction);
|
||||
instruction.delete();
|
||||
initBlock.add(instruction);
|
||||
JumpInstruction jumpToContinue = new JumpInstruction();
|
||||
jumpToContinue.setTarget(continueBlock);
|
||||
initBlock.getInstructions().add(jumpToContinue);
|
||||
initBlock.add(jumpToContinue);
|
||||
|
||||
createInitCheck(program, block, className, continueBlock, initBlock);
|
||||
|
||||
basicBlockMap[i] = continueBlock.getIndex();
|
||||
block = continueBlock;
|
||||
instructions = block.getInstructions();
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
BasicBlockMapper blockMapper = new BasicBlockMapper(index -> index + firstInlineBlock.getIndex());
|
||||
List<Phi> phis = new ArrayList<>(blockToInline.getPhis());
|
||||
blockToInline.getPhis().clear();
|
||||
inlineBlock.getPhis().addAll(phis);
|
||||
|
||||
List<TryCatchBlock> tryCatches = new ArrayList<>(blockToInline.getTryCatchBlocks());
|
||||
blockToInline.getTryCatchBlocks().clear();
|
||||
inlineBlock.getTryCatchBlocks().addAll(tryCatches);
|
||||
}
|
||||
|
||||
BasicBlockMapper blockMapper = new BasicBlockMapper((BasicBlock b) ->
|
||||
program.basicBlockAt(b.getIndex() + firstInlineBlock.getIndex()));
|
||||
InstructionVariableMapper variableMapper = new InstructionVariableMapper(var -> {
|
||||
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;
|
||||
int count = invoke.getArguments().size();
|
||||
invokeCount += invoke.getArguments().size();
|
||||
if (invoke.getInstance() != null) {
|
||||
count++;
|
||||
invokeCount++;
|
||||
}
|
||||
return count + 1;
|
||||
}).sum();
|
||||
complexity += instructions.size() - 1 - nopCount + invokeCount;
|
||||
}
|
||||
}
|
||||
complexity += block.instructionCount() - nopCount + invokeCount;
|
||||
Instruction lastInsn = block.getLastInstruction();
|
||||
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<>();
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 ");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -320,7 +320,7 @@ class UsageGenerator {
|
|||
var = program.createVariable();
|
||||
insn.setReceiver(var);
|
||||
|
||||
block.getInstructions().add(insn);
|
||||
block.add(insn);
|
||||
return var;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user