From ae5e1e49622969b0ea736b9997227afa95243a94 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 9 Dec 2016 00:07:58 +0300 Subject: [PATCH] Store instructions as double-linked list instead of ArrayList --- .../org/teavm/classlib/impl/JavacSupport.java | 10 +- .../org/teavm/classlib/impl/ScalaHacks.java | 28 ++- .../lambda/LambdaMetafactorySubstitutor.java | 21 +- .../java/lang/TConsoleOutputStreamStdout.java | 4 - .../teavm/classlib/java/lang/TInteger.java | 2 +- .../reflect/AnnotationDependencyListener.java | 4 - .../teavm/ast/decompilation/Decompiler.java | 6 +- .../org/teavm/ast/optimization/Optimizer.java | 13 +- .../optimization/ReadWriteStatsBuilder.java | 2 +- .../backend/javascript/JavaScriptTarget.java | 8 +- .../NullPointerExceptionTransformer.java | 5 +- .../org/teavm/backend/wasm/WasmTarget.java | 4 +- .../backend/wasm/patches/ClassPatch.java | 7 +- .../org/teavm/cache/DiskProgramCache.java | 6 +- .../main/java/org/teavm/cache/ProgramIO.java | 8 +- .../org/teavm/dependency/DependencyAgent.java | 4 - .../dependency/DependencyGraphBuilder.java | 19 +- .../java/org/teavm/dependency/Linker.java | 6 +- .../org/teavm/model/AnnotationContainer.java | 4 - .../model/AnnotationContainerReader.java | 4 - .../org/teavm/model/AnnotationReader.java | 4 - .../java/org/teavm/model/AnnotationValue.java | 4 - .../main/java/org/teavm/model/BasicBlock.java | 204 +++++++++++++----- .../org/teavm/model/BasicBlockReader.java | 2 +- .../java/org/teavm/model/Instruction.java | 132 +++++++++++- ...ormation.java => InstructionIterator.java} | 26 +-- .../teavm/model/InstructionReadVisitor.java | 8 +- .../org/teavm/model/InterpretException.java | 8 +- .../java/org/teavm/model/Interpreter.java | 11 +- .../analysis/NullnessInformationBuilder.java | 49 ++--- .../org/teavm/model/emit/ProgramEmitter.java | 8 +- .../teavm/model/emit/StringChooseEmitter.java | 6 +- .../instructions/ArrayLengthInstruction.java | 4 - .../model/instructions/EmptyInstruction.java | 4 - .../model/instructions/JumpInstruction.java | 4 - .../lowlevel/ClassInitializerEliminator.java | 8 +- .../lowlevel/ClassInitializerTransformer.java | 58 +++-- ...ceptionHandlingShadowStackContributor.java | 48 ++--- .../lowlevel/GCShadowStackContributor.java | 92 ++++---- .../lowlevel/ShadowStackTransformer.java | 8 +- .../model/optimization/ArrayUnwrapMotion.java | 44 ++-- .../optimization/ClassInitElimination.java | 12 +- .../ConstantConditionElimination.java | 4 +- .../model/optimization/Devirtualization.java | 6 +- .../optimization/EmptyBlockElimination.java | 4 +- .../optimization/GlobalValueNumbering.java | 13 +- .../teavm/model/optimization/Inlining.java | 80 ++++--- .../optimization/LoopInvariantMotion.java | 16 +- .../model/optimization/LoopInversionImpl.java | 14 +- .../RedundantJumpElimination.java | 14 +- .../UnusedVariableElimination.java | 6 +- .../optimization/VariableEscapeAnalyzer.java | 6 +- .../VariableUsageGraphBuilder.java | 2 +- .../model/text/InstructionStringifier.java | 5 +- .../org/teavm/model/text/ListingBuilder.java | 5 +- .../org/teavm/model/text/ListingParser.java | 6 +- .../model/util/AsyncProgramSplitter.java | 49 ++--- .../teavm/model/util/BasicBlockMapper.java | 146 +------------ .../model/util/InstructionVariableMapper.java | 2 +- .../model/util/InterferenceGraphBuilder.java | 3 +- .../teavm/model/util/LivenessAnalyzer.java | 2 +- .../model/util/LocationGraphBuilder.java | 2 +- .../model/util/MissingItemsProcessor.java | 18 +- .../java/org/teavm/model/util/ModelUtils.java | 4 - .../java/org/teavm/model/util/PhiUpdater.java | 46 ++-- .../util/ProgramNodeSplittingBackend.java | 5 +- .../org/teavm/model/util/ProgramUtils.java | 19 +- .../teavm/model/util/RegisterAllocator.java | 23 +- .../org/teavm/parsing/ClassRefsRenamer.java | 2 +- .../main/java/org/teavm/parsing/Parser.java | 4 +- .../java/org/teavm/parsing/ProgramParser.java | 11 +- .../java/org/teavm/cache/ProgramIOTest.java | 95 ++++---- .../java/org/teavm/model/text/ParserTest.java | 62 +----- .../main/java/org/teavm/html4j/JCLHacks.java | 24 +-- .../org/teavm/jso/impl/JSClassProcessor.java | 17 +- .../impl/CompositeMethodGenerator.java | 7 +- .../impl/MetaprogrammingImpl.java | 2 +- .../impl/ProxyVariableContext.java | 8 +- .../metaprogramming/impl/UsageGenerator.java | 2 +- .../impl/optimization/BoxingElimination.java | 17 +- .../plugin/ResourceProgramTransformer.java | 13 +- 81 files changed, 807 insertions(+), 866 deletions(-) rename core/src/main/java/org/teavm/model/{AsyncInformation.java => InstructionIterator.java} (57%) diff --git a/classlib/src/main/java/org/teavm/classlib/impl/JavacSupport.java b/classlib/src/main/java/org/teavm/classlib/impl/JavacSupport.java index cefd3bd3a..7021a559b 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/JavacSupport.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/JavacSupport.java @@ -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", "", 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); } } diff --git a/classlib/src/main/java/org/teavm/classlib/impl/ScalaHacks.java b/classlib/src/main/java/org/teavm/classlib/impl/ScalaHacks.java index cf3f4e481..470726f84 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/ScalaHacks.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/ScalaHacks.java @@ -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 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; diff --git a/classlib/src/main/java/org/teavm/classlib/impl/lambda/LambdaMetafactorySubstitutor.java b/classlib/src/main/java/org/teavm/classlib/impl/lambda/LambdaMetafactorySubstitutor.java index 44574d0af..9c5513db8 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/lambda/LambdaMetafactorySubstitutor.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/lambda/LambdaMetafactorySubstitutor.java @@ -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) { diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TConsoleOutputStreamStdout.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TConsoleOutputStreamStdout.java index 710dd3f4d..39250657d 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TConsoleOutputStreamStdout.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TConsoleOutputStreamStdout.java @@ -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") diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java index 439ab3c7a..253860aa6 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java @@ -32,7 +32,7 @@ public class TInteger extends TNumber implements TComparable { } 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(); diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/AnnotationDependencyListener.java b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/AnnotationDependencyListener.java index 4409675aa..41b56e434 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/AnnotationDependencyListener.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/AnnotationDependencyListener.java @@ -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) { diff --git a/core/src/main/java/org/teavm/ast/decompilation/Decompiler.java b/core/src/main/java/org/teavm/ast/decompilation/Decompiler.java index 527cfbbfb..1a1cb5261 100644 --- a/core/src/main/java/org/teavm/ast/decompilation/Decompiler.java +++ b/core/src/main/java/org/teavm/ast/decompilation/Decompiler.java @@ -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 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(); } diff --git a/core/src/main/java/org/teavm/ast/optimization/Optimizer.java b/core/src/main/java/org/teavm/ast/optimization/Optimizer.java index 7259d7035..d42e96421 100644 --- a/core/src/main/java/org/teavm/ast/optimization/Optimizer.java +++ b/core/src/main/java/org/teavm/ast/optimization/Optimizer.java @@ -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 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()); } diff --git a/core/src/main/java/org/teavm/ast/optimization/ReadWriteStatsBuilder.java b/core/src/main/java/org/teavm/ast/optimization/ReadWriteStatsBuilder.java index 7978a64b1..1b29da3a5 100644 --- a/core/src/main/java/org/teavm/ast/optimization/ReadWriteStatsBuilder.java +++ b/core/src/main/java/org/teavm/ast/optimization/ReadWriteStatsBuilder.java @@ -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()) { diff --git a/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java b/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java index 3583a0304..c5c135ccb 100644 --- a/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java +++ b/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java @@ -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, "", 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()); diff --git a/core/src/main/java/org/teavm/backend/javascript/NullPointerExceptionTransformer.java b/core/src/main/java/org/teavm/backend/javascript/NullPointerExceptionTransformer.java index 7ebdd12ad..475566f48 100644 --- a/core/src/main/java/org/teavm/backend/javascript/NullPointerExceptionTransformer.java +++ b/core/src/main/java/org/teavm/backend/javascript/NullPointerExceptionTransformer.java @@ -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); } } } diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java index 07b5ddd43..ed57305b4 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java @@ -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) { diff --git a/core/src/main/java/org/teavm/backend/wasm/patches/ClassPatch.java b/core/src/main/java/org/teavm/backend/wasm/patches/ClassPatch.java index 7b645eb7b..fc691beba 100644 --- a/core/src/main/java/org/teavm/backend/wasm/patches/ClassPatch.java +++ b/core/src/main/java/org/teavm/backend/wasm/patches/ClassPatch.java @@ -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); } } } diff --git a/core/src/main/java/org/teavm/cache/DiskProgramCache.java b/core/src/main/java/org/teavm/cache/DiskProgramCache.java index de6fc85ef..5da4a43be 100644 --- a/core/src/main/java/org/teavm/cache/DiskProgramCache.java +++ b/core/src/main/java/org/teavm/cache/DiskProgramCache.java @@ -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); } } diff --git a/core/src/main/java/org/teavm/cache/ProgramIO.java b/core/src/main/java/org/teavm/cache/ProgramIO.java index 944b4eaa2..eccdb63fe 100644 --- a/core/src/main/java/org/teavm/cache/ProgramIO.java +++ b/core/src/main/java/org/teavm/cache/ProgramIO.java @@ -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: { diff --git a/core/src/main/java/org/teavm/dependency/DependencyAgent.java b/core/src/main/java/org/teavm/dependency/DependencyAgent.java index 8c501bdee..a1749b015 100644 --- a/core/src/main/java/org/teavm/dependency/DependencyAgent.java +++ b/core/src/main/java/org/teavm/dependency/DependencyAgent.java @@ -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; diff --git a/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java b/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java index 0bd3a6776..309d2ca2b 100644 --- a/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java +++ b/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java @@ -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 splitInstructions = block.getInstructions().subList(j + 1, - block.getInstructions().size()); - List 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 arguments = new ArrayList<>(); for (int k = 0; k < indy.getArguments().size(); ++k) { diff --git a/core/src/main/java/org/teavm/dependency/Linker.java b/core/src/main/java/org/teavm/dependency/Linker.java index f6b7efaa7..2b2aad2f4 100644 --- a/core/src/main/java/org/teavm/dependency/Linker.java +++ b/core/src/main/java/org/teavm/dependency/Linker.java @@ -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) { diff --git a/core/src/main/java/org/teavm/model/AnnotationContainer.java b/core/src/main/java/org/teavm/model/AnnotationContainer.java index ef58854be..efeff7826 100644 --- a/core/src/main/java/org/teavm/model/AnnotationContainer.java +++ b/core/src/main/java/org/teavm/model/AnnotationContainer.java @@ -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 annotations = new HashMap<>(); diff --git a/core/src/main/java/org/teavm/model/AnnotationContainerReader.java b/core/src/main/java/org/teavm/model/AnnotationContainerReader.java index a79265728..a9f0f2d42 100644 --- a/core/src/main/java/org/teavm/model/AnnotationContainerReader.java +++ b/core/src/main/java/org/teavm/model/AnnotationContainerReader.java @@ -15,10 +15,6 @@ */ package org.teavm.model; -/** - * - * @author Alexey Andreev - */ public interface AnnotationContainerReader { AnnotationReader get(String type); diff --git a/core/src/main/java/org/teavm/model/AnnotationReader.java b/core/src/main/java/org/teavm/model/AnnotationReader.java index 64b598a85..8c9716994 100644 --- a/core/src/main/java/org/teavm/model/AnnotationReader.java +++ b/core/src/main/java/org/teavm/model/AnnotationReader.java @@ -15,10 +15,6 @@ */ package org.teavm.model; -/** - * - * @author Alexey Andreev - */ public interface AnnotationReader { String getType(); diff --git a/core/src/main/java/org/teavm/model/AnnotationValue.java b/core/src/main/java/org/teavm/model/AnnotationValue.java index 0a226ee5d..48de05dd0 100644 --- a/core/src/main/java/org/teavm/model/AnnotationValue.java +++ b/core/src/main/java/org/teavm/model/AnnotationValue.java @@ -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; diff --git a/core/src/main/java/org/teavm/model/BasicBlock.java b/core/src/main/java/org/teavm/model/BasicBlock.java index 963acb303..9b0e19465 100644 --- a/core/src/main/java/org/teavm/model/BasicBlock.java +++ b/core/src/main/java/org/teavm/model/BasicBlock.java @@ -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 { private Program program; private int index; private List phis = new ArrayList<>(); - private List instructions = new ArrayList<>(); private List 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 safeInstructions = new AbstractList() { - @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 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 iterator() { + return new Iterator() { + 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 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 instructions) { + Iterator 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 safePhis = new AbstractList() { @@ -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); diff --git a/core/src/main/java/org/teavm/model/BasicBlockReader.java b/core/src/main/java/org/teavm/model/BasicBlockReader.java index 64627dbce..a11d00021 100644 --- a/core/src/main/java/org/teavm/model/BasicBlockReader.java +++ b/core/src/main/java/org/teavm/model/BasicBlockReader.java @@ -27,7 +27,7 @@ public interface BasicBlockReader { int instructionCount(); - void readInstruction(int index, InstructionReader reader); + InstructionIterator iterateInstructions(); void readAllInstructions(InstructionReader reader); diff --git a/core/src/main/java/org/teavm/model/Instruction.java b/core/src/main/java/org/teavm/model/Instruction.java index f14c01a70..bc4cd176c 100644 --- a/core/src/main/java/org/teavm/model/Instruction.java +++ b/core/src/main/java/org/teavm/model/Instruction.java @@ -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 other) { + Iterator 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 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"); + } + } } diff --git a/core/src/main/java/org/teavm/model/AsyncInformation.java b/core/src/main/java/org/teavm/model/InstructionIterator.java similarity index 57% rename from core/src/main/java/org/teavm/model/AsyncInformation.java rename to core/src/main/java/org/teavm/model/InstructionIterator.java index f1e73b4b9..255ef1eca 100644 --- a/core/src/main/java/org/teavm/model/AsyncInformation.java +++ b/core/src/main/java/org/teavm/model/InstructionIterator.java @@ -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 syncMethods = new HashSet<>(); - private Set asyncMethods = new HashSet<>(); +public interface InstructionIterator { + boolean hasNext(); - public Set getSyncMethods() { - return syncMethods; - } + void next(); - public Set getAsyncMethods() { - return asyncMethods; - } + boolean hasPrevious(); + + void previous(); + + void read(InstructionReader reader); } diff --git a/core/src/main/java/org/teavm/model/InstructionReadVisitor.java b/core/src/main/java/org/teavm/model/InstructionReadVisitor.java index 49610fd85..3106730ea 100644 --- a/core/src/main/java/org/teavm/model/InstructionReadVisitor.java +++ b/core/src/main/java/org/teavm/model/InstructionReadVisitor.java @@ -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; diff --git a/core/src/main/java/org/teavm/model/InterpretException.java b/core/src/main/java/org/teavm/model/InterpretException.java index f9ab23833..d9d3c6b2e 100644 --- a/core/src/main/java/org/teavm/model/InterpretException.java +++ b/core/src/main/java/org/teavm/model/InterpretException.java @@ -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; - } } diff --git a/core/src/main/java/org/teavm/model/Interpreter.java b/core/src/main/java/org/teavm/model/Interpreter.java index 3a3a3652f..be402332b 100644 --- a/core/src/main/java/org/teavm/model/Interpreter.java +++ b/core/src/main/java/org/teavm/model/Interpreter.java @@ -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; diff --git a/core/src/main/java/org/teavm/model/analysis/NullnessInformationBuilder.java b/core/src/main/java/org/teavm/model/analysis/NullnessInformationBuilder.java index ec4a04bcb..d8a456fc2 100644 --- a/core/src/main/java/org/teavm/model/analysis/NullnessInformationBuilder.java +++ b/core/src/main/java/org/teavm/model/analysis/NullnessInformationBuilder.java @@ -60,7 +60,6 @@ class NullnessInformationBuilder { private PhiUpdater phiUpdater; private List nullInstructions = new ArrayList<>(); private List notNullInstructions = new ArrayList<>(); - private List> 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 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); } } diff --git a/core/src/main/java/org/teavm/model/emit/ProgramEmitter.java b/core/src/main/java/org/teavm/model/emit/ProgramEmitter.java index 58017e8eb..4b98cd893 100644 --- a/core/src/main/java/org/teavm/model/emit/ProgramEmitter.java +++ b/core/src/main/java/org/teavm/model/emit/ProgramEmitter.java @@ -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) { diff --git a/core/src/main/java/org/teavm/model/emit/StringChooseEmitter.java b/core/src/main/java/org/teavm/model/emit/StringChooseEmitter.java index 0e291d2b6..74b202f28 100644 --- a/core/src/main/java/org/teavm/model/emit/StringChooseEmitter.java +++ b/core/src/main/java/org/teavm/model/emit/StringChooseEmitter.java @@ -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); diff --git a/core/src/main/java/org/teavm/model/instructions/ArrayLengthInstruction.java b/core/src/main/java/org/teavm/model/instructions/ArrayLengthInstruction.java index 82dc76583..9f241e269 100644 --- a/core/src/main/java/org/teavm/model/instructions/ArrayLengthInstruction.java +++ b/core/src/main/java/org/teavm/model/instructions/ArrayLengthInstruction.java @@ -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; diff --git a/core/src/main/java/org/teavm/model/instructions/EmptyInstruction.java b/core/src/main/java/org/teavm/model/instructions/EmptyInstruction.java index 53871380b..cc48575b7 100644 --- a/core/src/main/java/org/teavm/model/instructions/EmptyInstruction.java +++ b/core/src/main/java/org/teavm/model/instructions/EmptyInstruction.java @@ -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) { diff --git a/core/src/main/java/org/teavm/model/instructions/JumpInstruction.java b/core/src/main/java/org/teavm/model/instructions/JumpInstruction.java index b22f1bfa5..511697e60 100644 --- a/core/src/main/java/org/teavm/model/instructions/JumpInstruction.java +++ b/core/src/main/java/org/teavm/model/instructions/JumpInstruction.java @@ -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; diff --git a/core/src/main/java/org/teavm/model/lowlevel/ClassInitializerEliminator.java b/core/src/main/java/org/teavm/model/lowlevel/ClassInitializerEliminator.java index 1a32fd72d..7c72a2836 100644 --- a/core/src/main/java/org/teavm/model/lowlevel/ClassInitializerEliminator.java +++ b/core/src/main/java/org/teavm/model/lowlevel/ClassInitializerEliminator.java @@ -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 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(); } } } diff --git a/core/src/main/java/org/teavm/model/lowlevel/ClassInitializerTransformer.java b/core/src/main/java/org/teavm/model/lowlevel/ClassInitializerTransformer.java index 61264c00c..2127247f0 100644 --- a/core/src/main/java/org/teavm/model/lowlevel/ClassInitializerTransformer.java +++ b/core/src/main/java/org/teavm/model/lowlevel/ClassInitializerTransformer.java @@ -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 instructions = block.getInstructions(); - for (int j = 0; j < instructions.size(); ++j) { - Instruction instruction = instructions.get(j); - if (instruction instanceof InitClassInstruction) { - String className = ((InitClassInstruction) instruction).getClassName(); - - BasicBlock continueBlock = program.createBasicBlock(); - List instructionsToMove = instructions.subList(j + 1, instructions.size()); - List instructionsToMoveCopy = new ArrayList<>(instructionsToMove); - instructionsToMove.clear(); - continueBlock.getInstructions().addAll(instructionsToMoveCopy); - continueBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program)); - - BasicBlock initBlock = program.createBasicBlock(); - instructions.remove(j); - initBlock.getInstructions().add(instruction); - JumpInstruction jumpToContinue = new JumpInstruction(); - jumpToContinue.setTarget(continueBlock); - initBlock.getInstructions().add(jumpToContinue); - - createInitCheck(program, block, className, continueBlock, initBlock); - - basicBlockMap[i] = continueBlock.getIndex(); - block = continueBlock; - instructions = block.getInstructions(); - j = 0; + for (Instruction instruction : block) { + if (!(instruction instanceof InitClassInstruction)) { + continue; } + String className = ((InitClassInstruction) instruction).getClassName(); + block = instruction.getBasicBlock(); + + BasicBlock continueBlock = program.createBasicBlock(); + while (instruction.getNext() != null) { + Instruction toMove = instruction.getNext(); + toMove.delete(); + continueBlock.add(toMove); + } + continueBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program)); + + BasicBlock initBlock = program.createBasicBlock(); + instruction.delete(); + initBlock.add(instruction); + JumpInstruction jumpToContinue = new JumpInstruction(); + jumpToContinue.setTarget(continueBlock); + initBlock.add(jumpToContinue); + + createInitCheck(program, block, className, continueBlock, initBlock); + + basicBlockMap[i] = continueBlock.getIndex(); } } @@ -94,19 +90,19 @@ public class ClassInitializerTransformer { ClassConstantInstruction clsConstant = new ClassConstantInstruction(); clsConstant.setReceiver(clsVariable); clsConstant.setConstant(ValueType.object(className)); - block.getInstructions().add(clsConstant); + block.add(clsConstant); InvokeInstruction checkInitialized = new InvokeInstruction(); checkInitialized.setType(InvocationType.SPECIAL); checkInitialized.setMethod(new MethodReference(Allocator.class, "isInitialized", Class.class, boolean.class)); checkInitialized.getArguments().add(clsVariable); checkInitialized.setReceiver(initializedVariable); - block.getInstructions().add(checkInitialized); + block.add(checkInitialized); BranchingInstruction branching = new BranchingInstruction(BranchingCondition.EQUAL); branching.setOperand(initializedVariable); branching.setConsequent(continueBlock); branching.setAlternative(initBlock); - block.getInstructions().add(branching); + block.add(branching); } } diff --git a/core/src/main/java/org/teavm/model/lowlevel/ExceptionHandlingShadowStackContributor.java b/core/src/main/java/org/teavm/model/lowlevel/ExceptionHandlingShadowStackContributor.java index 0c3b9fe71..3ac9ba48b 100644 --- a/core/src/main/java/org/teavm/model/lowlevel/ExceptionHandlingShadowStackContributor.java +++ b/core/src/main/java/org/teavm/model/lowlevel/ExceptionHandlingShadowStackContributor.java @@ -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 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 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 remainingInstructions = instructions.subList(i + 1, instructions.size()); - List 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 pre = setLocation(getInstructionsBeforeCallSite(callSite), insn.getLocation()); List 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 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; } diff --git a/core/src/main/java/org/teavm/model/lowlevel/GCShadowStackContributor.java b/core/src/main/java/org/teavm/model/lowlevel/GCShadowStackContributor.java index 8995e7008..cc4feb253 100644 --- a/core/src/main/java/org/teavm/model/lowlevel/GCShadowStackContributor.java +++ b/core/src/main/java/org/teavm/model/lowlevel/GCShadowStackContributor.java @@ -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> liveInInformation = findCallSiteLiveIns(program, method); + List> 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> liveInStores = reduceGCRootStores(program, usedColors, liveInInformation, + List> liveInStores = reduceGCRootStores(program, usedColors, liveInInformation, colors, autoSpilled); putLiveInGCRoots(program, liveInStores); @@ -119,11 +122,11 @@ public class GCShadowStackContributor { } } - private List> findCallSiteLiveIns(Program program, MethodReader method) { + private List> findCallSiteLiveIns(Program program, MethodReader method) { Graph cfg = ProgramUtils.buildControlFlowGraph(program); TypeInferer typeInferer = new TypeInferer(); typeInferer.inferTypes(program, method.getReference()); - List> liveInInformation = new ArrayList<>(); + List> 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 blockLiveIn = new IntObjectOpenHashMap<>(); + Map 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> liveInInformation, Program program) { + private Graph buildInterferenceGraph(List> liveInInformation, Program program) { GraphBuilder builder = new GraphBuilder(program.variableCount()); - for (IntObjectMap blockLiveIn : liveInInformation) { - for (ObjectCursor callSiteLiveIn : blockLiveIn.values()) { - BitSet liveVarsSet = callSiteLiveIn.value; + for (Map 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> liveInInformation, Program program) { + private boolean[] getAffectedVariables(List> liveInInformation, Program program) { boolean[] affectedVariables = new boolean[program.variableCount()]; - for (IntObjectMap blockLiveIn : liveInInformation) { - for (ObjectCursor callSiteLiveIn : blockLiveIn.values()) { - BitSet liveVarsSet = callSiteLiveIn.value; + for (Map 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> reduceGCRootStores(Program program, int usedColors, - List> liveInInformation, int[] colors, boolean[] autoSpilled) { + private List> reduceGCRootStores(Program program, int usedColors, + List> 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> slotsToUpdate = new ArrayList<>(); + List> 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 callSites = liveInInformation.get(step.node); - IntObjectMap updatesByCallSite = slotsToUpdate.get(step.node); - int[] callSiteLocations = callSites.keys().toArray(); - Arrays.sort(callSiteLocations); - for (int callSiteLocation : callSiteLocations) { + Map callSites = liveInInformation.get(step.node); + Map 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 sortInstructions(Collection instructions, BasicBlock block) { + ObjectIntMap indexes = new ObjectIntOpenHashMap<>(); + int index = 0; + for (Instruction instruction : block) { + indexes.put(instruction, index++); + } + List 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> updateInformation) { + private void putLiveInGCRoots(Program program, List> updateInformation) { for (int i = 0; i < program.basicBlockCount(); ++i) { BasicBlock block = program.basicBlockAt(i); - IntObjectMap 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 updatesByIndex = updateInformation.get(i); + Instruction[] callSiteLocations = updatesByIndex.keySet().toArray(new Instruction[0]); + ObjectIntMap 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 getInstructionIndexes(BasicBlock block) { + ObjectIntMap 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 instructions = block.getInstructions(); - Instruction callInstruction = instructions.get(index); List 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) { diff --git a/core/src/main/java/org/teavm/model/lowlevel/ShadowStackTransformer.java b/core/src/main/java/org/teavm/model/lowlevel/ShadowStackTransformer.java index 4afe75949..9393bb12b 100644 --- a/core/src/main/java/org/teavm/model/lowlevel/ShadowStackTransformer.java +++ b/core/src/main/java/org/teavm/model/lowlevel/ShadowStackTransformer.java @@ -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); } } diff --git a/core/src/main/java/org/teavm/model/optimization/ArrayUnwrapMotion.java b/core/src/main/java/org/teavm/model/optimization/ArrayUnwrapMotion.java index 9ec4f8bfc..74ebd6487 100644 --- a/core/src/main/java/org/teavm/model/optimization/ArrayUnwrapMotion.java +++ b/core/src/main/java/org/teavm/model/optimization/ArrayUnwrapMotion.java @@ -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 newInstructions = new ArrayList<>(); - List 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 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; } } diff --git a/core/src/main/java/org/teavm/model/optimization/ClassInitElimination.java b/core/src/main/java/org/teavm/model/optimization/ClassInitElimination.java index 9e93d885a..991eca540 100644 --- a/core/src/main/java/org/teavm/model/optimization/ClassInitElimination.java +++ b/core/src/main/java/org/teavm/model/optimization/ClassInitElimination.java @@ -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 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; } diff --git a/core/src/main/java/org/teavm/model/optimization/ConstantConditionElimination.java b/core/src/main/java/org/teavm/model/optimization/ConstantConditionElimination.java index fb9303fba..d4159cb91 100644 --- a/core/src/main/java/org/teavm/model/optimization/ConstantConditionElimination.java +++ b/core/src/main/java/org/teavm/model/optimization/ConstantConditionElimination.java @@ -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; } } diff --git a/core/src/main/java/org/teavm/model/optimization/Devirtualization.java b/core/src/main/java/org/teavm/model/optimization/Devirtualization.java index d9fcc971a..835ed903c 100644 --- a/core/src/main/java/org/teavm/model/optimization/Devirtualization.java +++ b/core/src/main/java/org/teavm/model/optimization/Devirtualization.java @@ -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; } diff --git a/core/src/main/java/org/teavm/model/optimization/EmptyBlockElimination.java b/core/src/main/java/org/teavm/model/optimization/EmptyBlockElimination.java index fd034cb6d..eaf0ee99c 100644 --- a/core/src/main/java/org/teavm/model/optimization/EmptyBlockElimination.java +++ b/core/src/main/java/org/teavm/model/optimization/EmptyBlockElimination.java @@ -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); diff --git a/core/src/main/java/org/teavm/model/optimization/GlobalValueNumbering.java b/core/src/main/java/org/teavm/model/optimization/GlobalValueNumbering.java index aabd02af7..39ce9c41b 100644 --- a/core/src/main/java/org/teavm/model/optimization/GlobalValueNumbering.java +++ b/core/src/main/java/org/teavm/model/optimization/GlobalValueNumbering.java @@ -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); } } } diff --git a/core/src/main/java/org/teavm/model/optimization/Inlining.java b/core/src/main/java/org/teavm/model/optimization/Inlining.java index e9a3e80e3..30c40af10 100644 --- a/core/src/main/java/org/teavm/model/optimization/Inlining.java +++ b/core/src/main/java/org/teavm/model/optimization/Inlining.java @@ -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 movedInstructions = block.getInstructions().subList(planEntry.targetInstruction + 1, - block.getInstructions().size()); - List 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("")) { InitClassInstruction clinit = new InitClassInstruction(); clinit.setClassName(invoke.getMethod().getClassName()); - block.getInstructions().add(clinit); + block.add(clinit); } JumpInstruction jumpToInlinedProgram = new JumpInstruction(); jumpToInlinedProgram.setTarget(firstInlineBlock); - block.getInstructions().add(jumpToInlinedProgram); + block.add(jumpToInlinedProgram); for (int i = 0; i < inlineProgram.basicBlockCount(); ++i) { BasicBlock blockToInline = inlineProgram.basicBlockAt(i); BasicBlock inlineBlock = program.basicBlockAt(firstInlineBlock.getIndex() + i); - ProgramUtils.copyBasicBlock(blockToInline, inlineBlock); + while (blockToInline.getFirstInstruction() != null) { + Instruction insn = blockToInline.getFirstInstruction(); + insn.delete(); + inlineBlock.add(insn); + } + + List phis = new ArrayList<>(blockToInline.getPhis()); + blockToInline.getPhis().clear(); + inlineBlock.getPhis().addAll(phis); + + List tryCatches = new ArrayList<>(blockToInline.getTryCatchBlocks()); + blockToInline.getTryCatchBlocks().clear(); + inlineBlock.getTryCatchBlocks().addAll(tryCatches); } - BasicBlockMapper blockMapper = new BasicBlockMapper(index -> index + firstInlineBlock.getIndex()); + BasicBlockMapper blockMapper = new BasicBlockMapper((BasicBlock b) -> + program.basicBlockAt(b.getIndex() + firstInlineBlock.getIndex())); InstructionVariableMapper variableMapper = new InstructionVariableMapper(var -> { if (var.getIndex() == 0) { return invoke.getInstance(); @@ -120,7 +134,7 @@ public class Inlining { ExitInstruction exit = (ExitInstruction) lastInsn; JumpInstruction exitReplacement = new JumpInstruction(); exitReplacement.setTarget(splitBlock); - mappedBlock.getInstructions().set(mappedBlock.getInstructions().size() - 1, exitReplacement); + exit.replace(exitReplacement); if (exit.getValueToReturn() != null) { Incoming resultIncoming = new Incoming(); resultIncoming.setSource(mappedBlock); @@ -135,7 +149,7 @@ public class Inlining { AssignInstruction resultAssignment = new AssignInstruction(); resultAssignment.setReceiver(invoke.getReceiver()); resultAssignment.setAssignee(resultVariables.get(0).getValue()); - splitBlock.getInstructions().add(0, resultAssignment); + splitBlock.addFirst(resultAssignment); } else { Phi resultPhi = new Phi(); resultPhi.setReceiver(invoke.getReceiver()); @@ -170,14 +184,11 @@ public class Inlining { List 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 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 instructions = block.getInstructions(); - int nopCount = (int) instructions.stream().filter(insn -> insn instanceof EmptyInstruction).count(); - int invokeCount = instructions.stream().mapToInt(insn -> { - if (!(insn instanceof InvokeInstruction)) { - return 0; + int nopCount = 0; + int invokeCount = 0; + for (Instruction insn : block) { + if (insn instanceof EmptyInstruction) { + nopCount++; + } else if (insn instanceof InvokeInstruction) { + InvokeInstruction invoke = (InvokeInstruction) insn; + invokeCount += invoke.getArguments().size(); + if (invoke.getInstance() != null) { + invokeCount++; + } } - InvokeInstruction invoke = (InvokeInstruction) insn; - int count = invoke.getArguments().size(); - if (invoke.getInstance() != null) { - count++; - } - return count + 1; - }).sum(); - complexity += instructions.size() - 1 - nopCount + invokeCount; + } + complexity += block.instructionCount() - nopCount + invokeCount; Instruction lastInsn = block.getLastInstruction(); if (lastInsn instanceof SwitchInstruction) { complexity += 3; @@ -248,7 +260,7 @@ public class Inlining { private class PlanEntry { int targetBlock; - int targetInstruction; + Instruction targetInstruction; Program program; final List innerPlan = new ArrayList<>(); } diff --git a/core/src/main/java/org/teavm/model/optimization/LoopInvariantMotion.java b/core/src/main/java/org/teavm/model/optimization/LoopInvariantMotion.java index e6ce37134..fd489ba17 100644 --- a/core/src/main/java/org/teavm/model/optimization/LoopInvariantMotion.java +++ b/core/src/main/java/org/teavm/model/optimization/LoopInvariantMotion.java @@ -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 preheaderInstructions = program.basicBlockAt(preheader).getInstructions(); + insn.replace(empty); + BasicBlock preheader = program.basicBlockAt(getPreheader(defLoop.getHead())); List 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)); } } diff --git a/core/src/main/java/org/teavm/model/optimization/LoopInversionImpl.java b/core/src/main/java/org/teavm/model/optimization/LoopInversionImpl.java index 2c9492ead..0c430b874 100644 --- a/core/src/main/java/org/teavm/model/optimization/LoopInversionImpl.java +++ b/core/src/main/java/org/teavm/model/optimization/LoopInversionImpl.java @@ -227,7 +227,7 @@ class LoopInversionImpl { } BasicBlock block = program.basicBlockAt(node); Set 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 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); diff --git a/core/src/main/java/org/teavm/model/optimization/RedundantJumpElimination.java b/core/src/main/java/org/teavm/model/optimization/RedundantJumpElimination.java index b42f56ea3..cc16a09d0 100644 --- a/core/src/main/java/org/teavm/model/optimization/RedundantJumpElimination.java +++ b/core/src/main/java/org/teavm/model/optimization/RedundantJumpElimination.java @@ -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 instructionsToTransfer = new ArrayList<>(target.getInstructions()); - target.getInstructions().clear(); - block.getInstructions().addAll(instructionsToTransfer); Instruction lastInsn = block.getLastInstruction(); if (lastInsn != null) { diff --git a/core/src/main/java/org/teavm/model/optimization/UnusedVariableElimination.java b/core/src/main/java/org/teavm/model/optimization/UnusedVariableElimination.java index 0f6f6e228..77972d278 100644 --- a/core/src/main/java/org/teavm/model/optimization/UnusedVariableElimination.java +++ b/core/src/main/java/org/teavm/model/optimization/UnusedVariableElimination.java @@ -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(); } } diff --git a/core/src/main/java/org/teavm/model/optimization/VariableEscapeAnalyzer.java b/core/src/main/java/org/teavm/model/optimization/VariableEscapeAnalyzer.java index 6c8762045..bd912112c 100644 --- a/core/src/main/java/org/teavm/model/optimization/VariableEscapeAnalyzer.java +++ b/core/src/main/java/org/teavm/model/optimization/VariableEscapeAnalyzer.java @@ -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); } } diff --git a/core/src/main/java/org/teavm/model/optimization/VariableUsageGraphBuilder.java b/core/src/main/java/org/teavm/model/optimization/VariableUsageGraphBuilder.java index 7752773f1..3fad34ec0 100644 --- a/core/src/main/java/org/teavm/model/optimization/VariableUsageGraphBuilder.java +++ b/core/src/main/java/org/teavm/model/optimization/VariableUsageGraphBuilder.java @@ -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()) { diff --git a/core/src/main/java/org/teavm/model/text/InstructionStringifier.java b/core/src/main/java/org/teavm/model/text/InstructionStringifier.java index 92f35e160..1bc9cbd0d 100644 --- a/core/src/main/java/org/teavm/model/text/InstructionStringifier.java +++ b/core/src/main/java/org/teavm/model/text/InstructionStringifier.java @@ -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()); } } diff --git a/core/src/main/java/org/teavm/model/text/ListingBuilder.java b/core/src/main/java/org/teavm/model/text/ListingBuilder.java index 460941588..4c19654a9 100644 --- a/core/src/main/java/org/teavm/model/text/ListingBuilder.java +++ b/core/src/main/java/org/teavm/model/text/ListingBuilder.java @@ -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 "); diff --git a/core/src/main/java/org/teavm/model/text/ListingParser.java b/core/src/main/java/org/teavm/model/text/ListingParser.java index bc52f5bed..9c6924799 100644 --- a/core/src/main/java/org/teavm/model/text/ListingParser.java +++ b/core/src/main/java/org/teavm/model/text/ListingParser.java @@ -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); } } diff --git a/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java b/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java index 8db3c37c7..eb63f02d9 100644 --- a/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java +++ b/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java @@ -46,7 +46,7 @@ import org.teavm.model.instructions.MonitorEnterInstruction; public class AsyncProgramSplitter { private List parts = new ArrayList<>(); - private Map partMap = new HashMap<>(); + private Map partMap = new HashMap<>(); private ClassReaderSource classSource; private Set 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 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 splitPoints; public AsyncProgramSplittingBackend(GraphSplittingBackend inner, IntegerArray blockSuccessors, - IntegerArray originalBlocks, IntegerArray splitPoints) { + IntegerArray originalBlocks, List 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)); diff --git a/core/src/main/java/org/teavm/model/util/BasicBlockMapper.java b/core/src/main/java/org/teavm/model/util/BasicBlockMapper.java index 301696bf9..1216d8c75 100644 --- a/core/src/main/java/org/teavm/model/util/BasicBlockMapper.java +++ b/core/src/main/java/org/teavm/model/util/BasicBlockMapper.java @@ -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 mapFunction; - public BasicBlockMapper(IntUnaryOperator mapFunction) { + public BasicBlockMapper(Function 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) { - } } diff --git a/core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java b/core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java index 55e1aeb67..528963c3a 100644 --- a/core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java +++ b/core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java @@ -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); } } diff --git a/core/src/main/java/org/teavm/model/util/InterferenceGraphBuilder.java b/core/src/main/java/org/teavm/model/util/InterferenceGraphBuilder.java index 5f78e8943..3fab77af1 100644 --- a/core/src/main/java/org/teavm/model/util/InterferenceGraphBuilder.java +++ b/core/src/main/java/org/teavm/model/util/InterferenceGraphBuilder.java @@ -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()) { diff --git a/core/src/main/java/org/teavm/model/util/LivenessAnalyzer.java b/core/src/main/java/org/teavm/model/util/LivenessAnalyzer.java index 429a8538b..cff039973 100644 --- a/core/src/main/java/org/teavm/model/util/LivenessAnalyzer.java +++ b/core/src/main/java/org/teavm/model/util/LivenessAnalyzer.java @@ -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()) { diff --git a/core/src/main/java/org/teavm/model/util/LocationGraphBuilder.java b/core/src/main/java/org/teavm/model/util/LocationGraphBuilder.java index 3a5199c92..5aa6de1cd 100644 --- a/core/src/main/java/org/teavm/model/util/LocationGraphBuilder.java +++ b/core/src/main/java/org/teavm/model/util/LocationGraphBuilder.java @@ -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()); diff --git a/core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java b/core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java index 71db2aea7..bed018031 100644 --- a/core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java +++ b/core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java @@ -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) { diff --git a/core/src/main/java/org/teavm/model/util/ModelUtils.java b/core/src/main/java/org/teavm/model/util/ModelUtils.java index 7be844a16..a56a7b3aa 100644 --- a/core/src/main/java/org/teavm/model/util/ModelUtils.java +++ b/core/src/main/java/org/teavm/model/util/ModelUtils.java @@ -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() { } diff --git a/core/src/main/java/org/teavm/model/util/PhiUpdater.java b/core/src/main/java/org/teavm/model/util/PhiUpdater.java index c3f0cb0ab..63e519dd2 100644 --- a/core/src/main/java/org/teavm/model/util/PhiUpdater.java +++ b/core/src/main/java/org/teavm/model/util/PhiUpdater.java @@ -90,19 +90,29 @@ public class PhiUpdater { private Phi[][] phiMap; private int[][] phiIndexMap; private Map> jointMap = new HashMap<>(); - private List> synthesizedPhis = new ArrayList<>(); + private List> synthesizedPhisByBlock = new ArrayList<>(); private IntObjectMap phisByReceiver = new IntObjectOpenHashMap<>(); private IntObjectMap jointsByReceiver = new IntObjectOpenHashMap<>(); private BitSet usedPhis = new BitSet(); - private List>> synthesizedJoints = new ArrayList<>(); + private List>> synthesizedJointsByBlock = new ArrayList<>(); private Variable[] originalExceptionVariables; private boolean[] usedDefinitions; private IntegerArray variableToSourceMap = new IntegerArray(10); + private List synthesizedPhis = new ArrayList<>(); + private List synthesizedJoints = new ArrayList<>(); public int getSourceVariable(int var) { return variableToSourceMap.get(var); } + public List getSynthesizedPhisBy() { + return synthesizedPhis; + } + + public List 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 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> joints = synthesizedJoints.get(i); + List> joints = synthesizedJointsByBlock.get(i); for (int j = 0; j < joints.size(); ++j) { List 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 phis = synthesizedPhis.get(successor); + List 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(); } diff --git a/core/src/main/java/org/teavm/model/util/ProgramNodeSplittingBackend.java b/core/src/main/java/org/teavm/model/util/ProgramNodeSplittingBackend.java index 3584ee3b5..e281a61fe 100644 --- a/core/src/main/java/org/teavm/model/util/ProgramNodeSplittingBackend.java +++ b/core/src/main/java/org/teavm/model/util/ProgramNodeSplittingBackend.java @@ -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; }); diff --git a/core/src/main/java/org/teavm/model/util/ProgramUtils.java b/core/src/main/java/org/teavm/model/util/ProgramUtils.java index d8ae03473..5bd457938 100644 --- a/core/src/main/java/org/teavm/model/util/ProgramUtils.java +++ b/core/src/main/java/org/teavm/model/util/ProgramUtils.java @@ -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 copyInstructions(BasicBlockReader block, int from, int to, Program target) { + public static List copyInstructions(Instruction from, Instruction to, Program target) { List 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; diff --git a/core/src/main/java/org/teavm/model/util/RegisterAllocator.java b/core/src/main/java/org/teavm/model/util/RegisterAllocator.java index 1f2da8065..ca4a4ddf4 100644 --- a/core/src/main/java/org/teavm/model/util/RegisterAllocator.java +++ b/core/src/main/java/org/teavm/model/util/RegisterAllocator.java @@ -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); diff --git a/core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java b/core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java index 065883cf1..a6857a945 100644 --- a/core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java +++ b/core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java @@ -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()) { diff --git a/core/src/main/java/org/teavm/parsing/Parser.java b/core/src/main/java/org/teavm/parsing/Parser.java index 4b4c8be53..5cf0a7fec 100644 --- a/core/src/main/java/org/teavm/parsing/Parser.java +++ b/core/src/main/java/org/teavm/parsing/Parser.java @@ -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 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()); diff --git a/core/src/main/java/org/teavm/parsing/ProgramParser.java b/core/src/main/java/org/teavm/parsing/ProgramParser.java index fa293e63c..77377ad3b 100644 --- a/core/src/main/java/org/teavm/parsing/ProgramParser.java +++ b/core/src/main/java/org/teavm/parsing/ProgramParser.java @@ -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 debugNames = new HashMap<>(accumulatedDebugNames); - variableDebugNames.put(basicBlock.getInstructions().get(0), debugNames); + variableDebugNames.put(basicBlock.getFirstInstruction(), debugNames); } } List 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; } diff --git a/core/src/test/java/org/teavm/cache/ProgramIOTest.java b/core/src/test/java/org/teavm/cache/ProgramIOTest.java index 53f8c871b..417fc4ff8 100644 --- a/core/src/test/java/org/teavm/cache/ProgramIOTest.java +++ b/core/src/test/java/org/teavm/cache/ProgramIOTest.java @@ -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) { diff --git a/core/src/test/java/org/teavm/model/text/ParserTest.java b/core/src/test/java/org/teavm/model/text/ParserTest.java index e4258ffaf..a9c8ba224 100644 --- a/core/src/test/java/org/teavm/model/text/ParserTest.java +++ b/core/src/test/java/org/teavm/model/text/ParserTest.java @@ -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 diff --git a/html4j/src/main/java/org/teavm/html4j/JCLHacks.java b/html4j/src/main/java/org/teavm/html4j/JCLHacks.java index 61a4fa0ed..65cb3cab2 100644 --- a/html4j/src/main/java/org/teavm/html4j/JCLHacks.java +++ b/html4j/src/main/java/org/teavm/html4j/JCLHacks.java @@ -19,10 +19,6 @@ import org.teavm.diagnostics.Diagnostics; import org.teavm.model.*; import org.teavm.model.instructions.*; -/** - * - * @author Alexey Andreev - */ public class JCLHacks implements ClassHolderTransformer { @Override public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { @@ -32,39 +28,33 @@ public class JCLHacks implements ClassHolderTransformer { } private void installThreadMethods(ClassHolder cls) { - cls.addMethod(createMethodThrowingSecurityException(new MethodDescriptor("setName", String.class, void.class), - false)); + cls.addMethod(createMethodThrowingSecurityException(new MethodDescriptor("setName", String.class, void.class))); cls.addMethod(createMethodThrowingSecurityException(new MethodDescriptor("setDaemon", - boolean.class, void.class), false)); + boolean.class, void.class))); } - private MethodHolder createMethodThrowingSecurityException(MethodDescriptor desc, boolean staticMethod) { + private MethodHolder createMethodThrowingSecurityException(MethodDescriptor desc) { MethodHolder method = new MethodHolder(desc); Program program = new Program(); for (int i = 0; i < desc.parameterCount(); ++i) { program.createVariable(); } - if (!staticMethod) { - program.createVariable(); - } + program.createVariable(); program.createVariable(); Variable var = program.createVariable(); BasicBlock block = program.createBasicBlock(); ConstructInstruction cons = new ConstructInstruction(); cons.setType("java.lang.SecurityException"); cons.setReceiver(var); - block.getInstructions().add(cons); + block.add(cons); InvokeInstruction invoke = new InvokeInstruction(); invoke.setType(InvocationType.SPECIAL); invoke.setInstance(var); invoke.setMethod(new MethodReference(SecurityException.class, "", 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; diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java b/jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java index 0c7a06a99..21051d473 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java @@ -270,9 +270,7 @@ class JSClassProcessor { program = methodToProcess.getProgram(); for (int i = 0; i < program.basicBlockCount(); ++i) { BasicBlock block = program.basicBlockAt(i); - List 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); diff --git a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/CompositeMethodGenerator.java b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/CompositeMethodGenerator.java index dab93e8af..59b22e707 100644 --- a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/CompositeMethodGenerator.java +++ b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/CompositeMethodGenerator.java @@ -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 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) { diff --git a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/MetaprogrammingImpl.java b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/MetaprogrammingImpl.java index 6967bd236..577894381 100644 --- a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/MetaprogrammingImpl.java +++ b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/MetaprogrammingImpl.java @@ -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); diff --git a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/ProxyVariableContext.java b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/ProxyVariableContext.java index f882db362..12e821bca 100644 --- a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/ProxyVariableContext.java +++ b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/ProxyVariableContext.java @@ -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(), "", 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); diff --git a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/UsageGenerator.java b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/UsageGenerator.java index dc5c404bc..f30c0b0fd 100644 --- a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/UsageGenerator.java +++ b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/UsageGenerator.java @@ -320,7 +320,7 @@ class UsageGenerator { var = program.createVariable(); insn.setReceiver(var); - block.getInstructions().add(insn); + block.add(insn); return var; } } diff --git a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/optimization/BoxingElimination.java b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/optimization/BoxingElimination.java index 36fc6ebf5..ccb21bb16 100644 --- a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/optimization/BoxingElimination.java +++ b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/optimization/BoxingElimination.java @@ -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 wrapperClasses = Arrays.asList(Boolean.class, Byte.class, Short.class, - Character.class, Integer.class, Long.class, Float.class, Double.class).stream() + private static Set 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); } } } diff --git a/platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java b/platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java index 87a2f46ac..a89e778ac 100644 --- a/platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java +++ b/platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java @@ -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 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 replacement = transformInvoke(invoke); if (replacement != null) { - instructions.set(i, new EmptyInstruction()); - instructions.addAll(i, replacement); - i += replacement.size(); + insn.insertNextAll(replacement); + insn.delete(); } } }