From af3547ab6113ea62ee3cc4c4890ee7ab41082798 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 30 Sep 2021 00:08:46 +0300 Subject: [PATCH] WIP --- .../newir/analysis/ExprConsumerCount.java | 75 +++ .../teavm/newir/expr/IrLongConstantExpr.java | 4 + .../newir/expr/RecursiveIrExprVisitor.java | 212 ++++++++ .../teavm/newir/interpreter/Interpreter.java | 9 +- ...erVisitor.java => InterpreterBuilder.java} | 479 +++++++----------- 5 files changed, 474 insertions(+), 305 deletions(-) create mode 100644 core/src/main/java/org/teavm/newir/analysis/ExprConsumerCount.java create mode 100644 core/src/main/java/org/teavm/newir/expr/RecursiveIrExprVisitor.java rename core/src/main/java/org/teavm/newir/interpreter/{InterpreterBuilderVisitor.java => InterpreterBuilder.java} (66%) diff --git a/core/src/main/java/org/teavm/newir/analysis/ExprConsumerCount.java b/core/src/main/java/org/teavm/newir/analysis/ExprConsumerCount.java new file mode 100644 index 000000000..795fcff30 --- /dev/null +++ b/core/src/main/java/org/teavm/newir/analysis/ExprConsumerCount.java @@ -0,0 +1,75 @@ +/* + * Copyright 2021 konsoletyper. + * + * 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.newir.analysis; + +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; +import org.teavm.newir.expr.IrExpr; +import org.teavm.newir.expr.IrSequenceExpr; +import org.teavm.newir.expr.IrUnaryExpr; +import org.teavm.newir.expr.IrUnaryOperation; +import org.teavm.newir.expr.RecursiveIrExprVisitor; + +public class ExprConsumerCount extends RecursiveIrExprVisitor { + private ObjectIntMap countMap = new ObjectIntHashMap<>(); + private ObjectIntMap ignoreMap = new ObjectIntHashMap<>(); + + public int get(IrExpr expr) { + return countMap.get(expr); + } + + public int getIgnored(IrExpr expr) { + return ignoreMap.get(expr); + } + + public int decAndGet(IrExpr expr) { + int count = countMap.get(expr); + if (count > 0) { + countMap.put(expr, --count); + } else { + throw new IllegalStateException("Trying to decrement beyond zero"); + } + return count; + } + + @Override + protected void visitDefault(IrExpr expr) { + int count = countMap.get(expr); + countMap.put(expr, count + 1); + if (count == 0) { + visitInputs(expr); + } + } + + @Override + public void visit(IrSequenceExpr expr) { + ignore(expr.getFirst()); + visitDefault(expr); + } + + @Override + public void visit(IrUnaryExpr expr) { + if (expr.getOperation() == IrUnaryOperation.IGNORE) { + ignore(expr.getArgument()); + } else { + super.visit(expr); + } + } + + private void ignore(IrExpr expr) { + ignoreMap.put(expr, ignoreMap.get(expr) + 1); + } +} diff --git a/core/src/main/java/org/teavm/newir/expr/IrLongConstantExpr.java b/core/src/main/java/org/teavm/newir/expr/IrLongConstantExpr.java index 04d4e6b78..07193e612 100644 --- a/core/src/main/java/org/teavm/newir/expr/IrLongConstantExpr.java +++ b/core/src/main/java/org/teavm/newir/expr/IrLongConstantExpr.java @@ -22,6 +22,10 @@ public final class IrLongConstantExpr extends IrExpr { this.value = value; } + public long getValue() { + return value; + } + @Override public IrType getType() { return IrType.LONG; diff --git a/core/src/main/java/org/teavm/newir/expr/RecursiveIrExprVisitor.java b/core/src/main/java/org/teavm/newir/expr/RecursiveIrExprVisitor.java new file mode 100644 index 000000000..1f7a514dd --- /dev/null +++ b/core/src/main/java/org/teavm/newir/expr/RecursiveIrExprVisitor.java @@ -0,0 +1,212 @@ +/* + * Copyright 2021 konsoletyper. + * + * 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.newir.expr; + +public class RecursiveIrExprVisitor implements IrExprVisitor { + protected final void visitInputs(IrExpr expr) { + for (int i = 0; i < expr.getInputCount(); ++i) { + expr.getInput(i).acceptVisitor(this); + } + } + + protected void visitDefault(IrExpr expr) { + } + + @Override + public void visit(IrSequenceExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrBlockExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrExitBlockExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrLoopExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrLoopHeaderExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrExitLoopExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrContinueLoopExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrTupleExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrTupleComponentExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrConditionalExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrNullaryExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrUnaryExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrBinaryExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrArrayElementExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrSetArrayElementExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrThrowExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrTryCatchExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrCaughtExceptionExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrCaughtValueExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrBoundsCheckExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrCastExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrInstanceOfExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrCallExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrGetFieldExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrGetStaticFieldExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrSetFieldExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrSetStaticFieldExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrNewObjectExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrNewArrayExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrParameterExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrVariableExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrSetVariableExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrIntConstantExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrLongConstantExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrFloatConstantExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrDoubleConstantExpr expr) { + visitDefault(expr); + } + + @Override + public void visit(IrStringConstantExpr expr) { + visitDefault(expr); + } +} diff --git a/core/src/main/java/org/teavm/newir/interpreter/Interpreter.java b/core/src/main/java/org/teavm/newir/interpreter/Interpreter.java index 41a1b1bd6..901ab5b52 100644 --- a/core/src/main/java/org/teavm/newir/interpreter/Interpreter.java +++ b/core/src/main/java/org/teavm/newir/interpreter/Interpreter.java @@ -19,6 +19,7 @@ import com.carrotsearch.hppc.ObjectIntHashMap; import com.carrotsearch.hppc.ObjectIntMap; import java.io.PrintWriter; import java.util.List; +import org.teavm.newir.analysis.ExprConsumerCount; import org.teavm.newir.expr.IrFunction; import org.teavm.newir.expr.IrParameter; import org.teavm.newir.expr.IrVariable; @@ -84,9 +85,11 @@ public class Interpreter { } } - InterpreterBuilderVisitor visitor = new InterpreterBuilderVisitor(intIndex, longIndex, floatIndex, - doubleIndex, objectIndex, parameterMap, variableMap); - function.getBody().acceptVisitor(visitor); + ExprConsumerCount consumerCount = new ExprConsumerCount(); + function.getBody().acceptVisitor(consumerCount); + InterpreterBuilder visitor = new InterpreterBuilder(intIndex, longIndex, floatIndex, + doubleIndex, objectIndex, parameterMap, variableMap, consumerCount); + visitor.build(function.getBody()); visitor.builder.add(Instructions.stop()); ctx = new InterpreterContext(visitor.getMaxIntIndex(), visitor.getMaxLongIndex(), visitor.getMaxFloatIndex(), diff --git a/core/src/main/java/org/teavm/newir/interpreter/InterpreterBuilderVisitor.java b/core/src/main/java/org/teavm/newir/interpreter/InterpreterBuilder.java similarity index 66% rename from core/src/main/java/org/teavm/newir/interpreter/InterpreterBuilderVisitor.java rename to core/src/main/java/org/teavm/newir/interpreter/InterpreterBuilder.java index b0c9d272f..64171978e 100644 --- a/core/src/main/java/org/teavm/newir/interpreter/InterpreterBuilderVisitor.java +++ b/core/src/main/java/org/teavm/newir/interpreter/InterpreterBuilder.java @@ -18,17 +18,14 @@ package org.teavm.newir.interpreter; import static org.teavm.newir.interpreter.instructions.Instructions.directJump; import static org.teavm.newir.interpreter.instructions.Instructions.dmov; import static org.teavm.newir.interpreter.instructions.Instructions.fmov; -import static org.teavm.newir.interpreter.instructions.Instructions.icst; import static org.teavm.newir.interpreter.instructions.Instructions.imov; import static org.teavm.newir.interpreter.instructions.Instructions.jumpIfFalse; import static org.teavm.newir.interpreter.instructions.Instructions.jumpIfTrue; import static org.teavm.newir.interpreter.instructions.Instructions.lmov; import static org.teavm.newir.interpreter.instructions.Instructions.omov; import com.carrotsearch.hppc.IntStack; -import com.carrotsearch.hppc.ObjectHashSet; import com.carrotsearch.hppc.ObjectIntHashMap; import com.carrotsearch.hppc.ObjectIntMap; -import com.carrotsearch.hppc.ObjectSet; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -36,6 +33,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.IntConsumer; +import org.teavm.newir.analysis.ExprConsumerCount; import org.teavm.newir.expr.IrArrayElementExpr; import org.teavm.newir.expr.IrBinaryExpr; import org.teavm.newir.expr.IrBlockExpr; @@ -84,7 +82,7 @@ import org.teavm.newir.interpreter.instructions.ArithmeticInstructions; import org.teavm.newir.interpreter.instructions.Instructions; import org.teavm.newir.interpreter.instructions.JavaInstructions; -public class InterpreterBuilderVisitor implements IrExprVisitor { +public class InterpreterBuilder implements IrExprVisitor { public int resultSlot; public final ProgramBuilder builder = new ProgramBuilder(); @@ -96,8 +94,7 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { private ObjectIntMap pendingConsumers = new ObjectIntHashMap<>(); private ObjectIntMap exprSlots = new ObjectIntHashMap<>(); - private Set borrowedSlots = new HashSet<>(); - private ObjectSet done = new ObjectHashSet<>(); + private Set visited = new HashSet<>(); private Map> loopBreaks = new HashMap<>(); private ObjectIntMap loopHeaders = new ObjectIntHashMap<>(); private Map> blockBreaks = new HashMap<>(); @@ -112,15 +109,17 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { private IntStack freeFloatSlots = new IntStack(); private IntStack freeDoubleSlots = new IntStack(); private IntStack freeObjectSlots = new IntStack(); + private ExprConsumerCount consumerCount; - public InterpreterBuilderVisitor( + public InterpreterBuilder( int intIndex, int longIndex, int floatIndex, int doubleIndex, int objectIndex, ObjectIntMap parameterSlots, - ObjectIntMap variableSlots + ObjectIntMap variableSlots, + ExprConsumerCount consumerCount ) { maxIntIndex = intIndex; maxLongIndex = longIndex; @@ -129,6 +128,144 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { maxObjectIndex = objectIndex; this.parameterSlots = parameterSlots; this.variableSlots = variableSlots; + this.consumerCount = consumerCount; + } + + public int build(IrExpr expr) { + int result = exprSlots.getOrDefault(expr, -1); + int remaining = consumerCount.decAndGet(expr); + int ignoreCount = consumerCount.getIgnored(expr); + + if (result < 0) { + if (result == -2) { + throw new IllegalStateException("Cycle found in IR"); + } + exprSlots.put(expr, -2); + + int resultSlotBackup = resultSlot; + if (remaining >= ignoreCount) { + result = getSlotFromPool(expr); + resultSlot = result; + } else { + throw new IllegalStateException(); + } + expr.acceptVisitor(this); + resultSlot = resultSlotBackup; + if (remaining > 0) { + exprSlots.put(expr, result); + } + } + + if (remaining == ignoreCount) { + returnSlotToPool(expr, exprSlots.get(expr)); + } + if (remaining == 0) { + exprSlots.remove(expr); + } + + return result; + } + + private void buildIgnoring(IrExpr expr) { + int result = exprSlots.getOrDefault(expr, -1); + int remaining = consumerCount.decAndGet(expr); + int ignoreCount = consumerCount.getIgnored(expr); + + if (result < 0) { + if (result == -2) { + throw new IllegalStateException("Cycle found in IR"); + } + exprSlots.put(expr, -2); + + int resultSlotBackup = resultSlot; + resultSlot = -1; + expr.acceptVisitor(this); + resultSlot = resultSlotBackup; + if (remaining > 0) { + exprSlots.put(expr, remaining >= ignoreCount ? getSlotFromPool(expr) : 0); + } + } + + if (remaining == ignoreCount) { + returnSlotToPool(expr, exprSlots.get(expr)); + } + if (remaining == 0) { + exprSlots.remove(expr); + } + } + + public void buildTo(IrExpr expr, int result) { + int actualSlot = exprSlots.getOrDefault(expr, -1); + int remaining = consumerCount.decAndGet(expr); + + if (actualSlot >= 0) { + if (actualSlot != result) { + move(expr.getType(), actualSlot, result); + } + } else { + if (actualSlot == -2) { + throw new IllegalStateException("Cycle found in IR"); + } + exprSlots.put(expr, -2); + int resultSlotBackup = resultSlot; + resultSlot = result; + expr.acceptVisitor(this); + resultSlot = resultSlotBackup; + if (remaining > 0) { + exprSlots.put(expr, result); + } + } + + if (remaining == 0) { + exprSlots.remove(expr); + } + } + + private int getSlotFromPool(IrExpr expr) { + switch (expr.getType().getKind()) { + case BOOLEAN: + case BYTE: + case SHORT: + case CHAR: + case INT: + return freeIntSlots.isEmpty() ? maxIntIndex++ : freeIntSlots.pop(); + case LONG: + return freeLongSlots.isEmpty() ? maxLongIndex++ : freeLongSlots.pop(); + case FLOAT: + return freeFloatSlots.isEmpty() ? maxFloatIndex++ : freeFloatSlots.pop(); + case DOUBLE: + return freeDoubleSlots.isEmpty() ? maxDoubleIndex : freeDoubleSlots.pop(); + default: + return 0; + } + } + + private void returnSlotToPool(IrExpr expr, int slot) { + switch (expr.getType().getKind()) { + case BOOLEAN: + case BYTE: + case SHORT: + case CHAR: + case INT: + freeIntSlots.add(slot); + break; + case LONG: + freeLongSlots.add(slot); + break; + case FLOAT: + freeFloatSlots.add(slot); + break; + case DOUBLE: + freeDoubleSlots.add(slot); + break; + case OBJECT: + freeObjectSlots.add(slot); + break; + case UNREACHABLE: + case VOID: + case TUPLE: + break; + } } public int getMaxIntIndex() { @@ -157,66 +294,41 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { @Override public void visit(IrSequenceExpr expr) { - if (checkDone(expr)) { - return; - } - - alloc(expr.getSecond()); - expr.getFirst().acceptVisitor(this); - expr.getSecond().acceptVisitor(this); - release(expr.getSecond()); + buildIgnoring(expr.getFirst()); + build(expr.getSecond()); } @Override public void visit(IrBlockExpr expr) { - if (checkDone(expr)) { - return; - } - List thisBlockBreaks = new ArrayList<>(); blockBreaks.put(expr, thisBlockBreaks); - expr.getBody().acceptVisitor(this); + buildTo(expr.getBody(), resultSlot); blockBreaks.remove(expr); for (IntConsumer blockBreak : thisBlockBreaks) { blockBreak.accept(builder.label()); } - - resultSlot = -1; } @Override public void visit(IrExitBlockExpr expr) { - if (checkDone(expr)) { - return; - } - - if (checkDone(expr)) { - return; - } - IntConsumer jump = suggestedJump != null && suggestedJumpLabel == builder.label() ? suggestedJump : builder.addJump(directJump()); blockBreaks.get(expr.getBlock()).add(jump); - resultSlot = -1; } @Override public void visit(IrLoopExpr expr) { - if (checkDone(expr)) { - return; - } - - expr.getPreheader().acceptVisitor(this); + build(expr.getPreheader()); int headerLabel = builder.label(); loopHeaders.put(expr, headerLabel); List thisLoopBreaks = new ArrayList<>(); loopBreaks.put(expr, thisLoopBreaks); - expr.getBody().acceptVisitor(this); + build(expr.getBody()); builder.addJump(directJump(headerLabel)); for (IntConsumer breakConsumer : thisLoopBreaks) { @@ -225,58 +337,41 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { loopHeaders.remove(expr); loopBreaks.remove(expr); - resultSlot = -1; } @Override public void visit(IrLoopHeaderExpr expr) { - checkDone(expr); } @Override public void visit(IrExitLoopExpr expr) { - if (checkDone(expr)) { - return; - } - IntConsumer jump = suggestedJump != null && suggestedJumpLabel == builder.label() ? suggestedJump : builder.addJump(directJump()); loopBreaks.get(expr.getLoop()).add(jump); - resultSlot = -1; } @Override public void visit(IrContinueLoopExpr expr) { - if (checkDone(expr)) { - return; - } int header = loopHeaders.get(expr.getLoop()); if (suggestedJump != null && suggestedJumpLabel == builder.label()) { suggestedJump.accept(header); } else { builder.addJump(directJump(header)); } - resultSlot = -1; } @Override public void visit(IrTupleExpr expr) { - } @Override public void visit(IrTupleComponentExpr expr) { - } @Override public void visit(IrConditionalExpr expr) { - int slot = resultSlot(expr); - - alloc(expr.getCondition()); - expr.getCondition().acceptVisitor(this); requestJumps(expr.getCondition()); IntConsumer trueJump = whenTrue; IntConsumer falseJump = whenFalse; @@ -286,10 +381,7 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { IntConsumer suggestedJumpBackup = suggestedJump; suggestedJump = trueJump; suggestedJumpLabel = builder.label(); - alloc(expr.getThenExpr()); - forceResultSlot(expr.getThenExpr(), slot); - expr.getThenExpr().acceptVisitor(this); - release(expr.getThenExpr()); + buildTo(expr.getThenExpr(), resultSlot); IntConsumer jumpAfterCondition = builder.label() != thenLabel && expr.getThenExpr().getType().getKind() != IrTypeKind.UNREACHABLE @@ -301,10 +393,7 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { } else { falseJump.accept(builder.label()); } - alloc(expr.getElseExpr()); - forceResultSlot(expr.getThenExpr(), slot); - expr.getElseExpr().acceptVisitor(this); - release(expr.getElseExpr()); + buildTo(expr.getThenExpr(), resultSlot); if (jumpAfterCondition != null) { jumpAfterCondition.accept(builder.label()); @@ -314,9 +403,6 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { suggestedJump = suggestedJumpBackup; suggestedJumpLabel = suggestedJumpPtrBackup; - - release(expr.getCondition()); - resultSlot = slot; } @Override @@ -326,10 +412,6 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { @Override public void visit(IrUnaryExpr expr) { - if (checkDone(expr)) { - return; - } - switch (expr.getOperation()) { } @@ -337,10 +419,6 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { @Override public void visit(IrBinaryExpr expr) { - if (checkDone(expr)) { - return; - } - switch (expr.getOperation()) { case IADD: simpleBinary(expr, ArithmeticInstructions::iadd); @@ -479,34 +557,19 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { } private void simpleBinary(IrBinaryExpr expr, BinaryInstructionFactory factory) { - alloc(expr.getFirst()); - alloc(expr.getSecond()); - expr.getFirst().acceptVisitor(this); - int a = resultSlot; - expr.getSecond().acceptVisitor(this); - int b = resultSlot; - release(expr.getSecond()); - release(expr.getFirst()); - - int r = resultSlot(expr); - this.resultSlot = r; - if (r > 0) { - builder.add(factory.create(r, a, b)); + int a = build(expr.getFirst()); + int b = build(expr.getSecond()); + if (resultSlot > 0) { + builder.add(factory.create(resultSlot, a, b)); } } private void logicalAnd(IrBinaryExpr expr) { - alloc(expr.getFirst()); requestJumps(expr.getFirst()); - release(expr.getFirst()); whenTrue.accept(builder.label()); IntConsumer firstWhenFalse = whenFalse; - alloc(expr.getSecond()); - saveBooleanIfNecessary(expr.getSecond()); - release(expr.getSecond()); - IntConsumer secondWhenTrue = whenTrue; IntConsumer secondWhenFalse = whenFalse; @@ -519,7 +582,6 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { firstWhenFalse.accept(label); secondWhenTrue.accept(ptr); }; - saveBooleanIfNecessary(expr); } private void logicalOr(IrBinaryExpr expr) { @@ -527,27 +589,14 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { } private void requestJumps(IrExpr expr) { - expr.acceptVisitor(this); + int condition = build(expr); if (whenTrue == null) { - int condition = resultSlot; int label = builder.emptySlot(); whenTrue = targetLabel -> builder.putInSlot(label, jumpIfTrue(targetLabel, condition)); whenFalse = targetLabel -> builder.putInSlot(label, jumpIfFalse(targetLabel, condition)); } } - private void saveBooleanIfNecessary(IrExpr expr) { - if (pendingConsumers.getOrDefault(expr, 0) != 1) { - int slot = resultSlot(expr); - whenTrue.accept(builder.label()); - builder.add(icst(slot, 1)); - IntConsumer gotoInsn = builder.addJump(directJump()); - whenFalse.accept(builder.label()); - builder.add(icst(slot, 0)); - gotoInsn.accept(builder.label()); - } - } - @Override public void visit(IrThrowExpr expr) { @@ -585,20 +634,11 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { @Override public void visit(IrCallExpr expr) { - if (checkDone(expr)) { - return; - } - - for (int i = 0; i < expr.getInputCount(); ++i) { - alloc(expr.getInput(i)); - } - int firstArg; int instance; if (expr.getCallType() != IrCallType.STATIC) { firstArg = 1; - expr.getInput(0).acceptVisitor(this); - instance = resultSlot; + instance = build(expr.getInput(0)); } else { firstArg = 0; instance = -1; @@ -606,49 +646,27 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { int[] arguments = new int[expr.getInputCount() - firstArg]; for (int i = firstArg; i < expr.getInputCount(); ++i) { - expr.getInput(i).acceptVisitor(this); - arguments[i - firstArg] = resultSlot; + arguments[i - firstArg] = build(expr.getInput(i)); } - for (int i = 0; i < expr.getInputCount(); ++i) { - release(expr.getInput(i)); - } - - int slot = resultSlot(expr); - - builder.add(JavaInstructions.call(slot, expr.getMethod(), instance, arguments)); - - resultSlot = slot; + builder.add(JavaInstructions.call(resultSlot, expr.getMethod(), instance, arguments)); } @Override public void visit(IrGetFieldExpr expr) { - if (checkDone(expr)) { - return; + int objectSlot = build(expr.getArgument()); + if (resultSlot >= 0) { + builder.add(JavaInstructions.getField(resultSlot, expr.getField(), expr.getFieldType(), objectSlot)); } - - alloc(expr.getArgument()); - expr.getArgument().acceptVisitor(this); - release(expr.getArgument()); - int objectSlot = resultSlot; - - int slot = resultSlot(expr); - builder.add(JavaInstructions.getField(slot, expr.getField(), expr.getFieldType(), objectSlot)); - resultSlot = slot; } @Override public void visit(IrGetStaticFieldExpr expr) { - if (checkDone(expr)) { - return; + if (resultSlot >= 0) { + builder.add(JavaInstructions.getField(resultSlot, expr.getField(), expr.getFieldType(), -1)); } - - int slot = resultSlot(expr); - builder.add(JavaInstructions.getField(slot, expr.getField(), expr.getFieldType(), -1)); - resultSlot = slot; } - @Override public void visit(IrSetFieldExpr expr) { @@ -681,44 +699,39 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { @Override public void visit(IrSetVariableExpr expr) { - if (checkDone(expr)) { - return; - } - - alloc(expr.getArgument()); - expr.getArgument().acceptVisitor(this); - int valueSlot = resultSlot; + int valueSlot = build(expr.getArgument()); int targetSlot = variableSlots.get(expr.getVariable()); if (valueSlot >= 0) { move(expr.getVariable().getType(), valueSlot, targetSlot); } - release(expr.getArgument()); - resultSlot = -1; } @Override public void visit(IrIntConstantExpr expr) { - if (checkDone(expr)) { - return; + if (resultSlot >= 0) { + builder.add(Instructions.icst(resultSlot, expr.getValue())); } - int slot = resultSlot(expr); - builder.add(Instructions.icst(slot, expr.getValue())); - resultSlot = slot; } @Override public void visit(IrLongConstantExpr expr) { - + if (resultSlot >= 0) { + builder.add(Instructions.lcst(resultSlot, expr.getValue())); + } } @Override public void visit(IrFloatConstantExpr expr) { - + if (resultSlot >= 0) { + builder.add(Instructions.fcst(resultSlot, expr.getValue())); + } } @Override public void visit(IrDoubleConstantExpr expr) { - + if (resultSlot >= 0) { + builder.add(Instructions.dcst(resultSlot, expr.getValue())); + } } @Override @@ -736,62 +749,6 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { } - private void alloc(IrExpr expr) { - pendingConsumers.put(expr, pendingConsumers.getOrDefault(expr, 0) + 1); - } - - private void release(IrExpr expr) { - int newCount = pendingConsumers.getOrDefault(expr, 0) - 1; - if (newCount == 0) { - pendingConsumers.remove(expr); - int slot = exprSlots.getOrDefault(expr, -1); - if (slot >= 0 && borrowedSlots.remove(expr)) { - exprSlots.remove(expr); - switch (expr.getType().getKind()) { - case BOOLEAN: - case BYTE: - case SHORT: - case CHAR: - case INT: - freeIntSlots.add(slot); - break; - case LONG: - freeLongSlots.add(slot); - break; - case FLOAT: - freeFloatSlots.add(slot); - break; - case DOUBLE: - freeDoubleSlots.add(slot); - break; - case OBJECT: - freeObjectSlots.add(slot); - break; - case UNREACHABLE: - case VOID: - case TUPLE: - break; - } - } - } else { - pendingConsumers.put(expr, newCount); - } - } - - private int resultSlot(IrExpr expr) { - return resultSlot(expr, -1); - } - - private void forceResultSlot(IrExpr expr, int slot) { - if (slot == -1) { - return; - } - int actual = resultSlot(expr, slot); - if (actual != -1 && actual != slot) { - move(expr.getType(), actual, slot); - } - } - private void move(IrType type, int from, int to) { if (from == to || to == -1) { return; @@ -820,88 +777,6 @@ public class InterpreterBuilderVisitor implements IrExprVisitor { } } - private int resultSlot(IrExpr expr, int suggested) { - if (pendingConsumers.getOrDefault(expr, 0) == 0) { - return -1; - } - int slot = exprSlots.getOrDefault(expr, -1); - if (slot < 0) { - switch (expr.getType().getKind()) { - case BOOLEAN: - case BYTE: - case SHORT: - case CHAR: - case INT: { - if (suggested >= 0) { - slot = suggested; - borrowedSlots.add(expr); - } else if (freeIntSlots.isEmpty()) { - slot = maxIntIndex++; - } else { - slot = freeIntSlots.pop(); - } - break; - } - case LONG: - if (suggested >= 0) { - slot = suggested; - borrowedSlots.add(expr); - } else if (freeLongSlots.isEmpty()) { - slot = maxLongIndex++; - } else { - slot = freeLongSlots.pop(); - } - break; - case FLOAT: - if (suggested >= 0) { - slot = suggested; - borrowedSlots.add(expr); - } else if (freeFloatSlots.isEmpty()) { - slot = maxFloatIndex++; - } else { - slot = freeFloatSlots.pop(); - } - break; - case DOUBLE: - if (suggested >= 0) { - slot = suggested; - borrowedSlots.add(expr); - } else if (freeDoubleSlots.isEmpty()) { - slot = maxDoubleIndex++; - } else { - slot = freeDoubleSlots.pop(); - } - break; - case OBJECT: - if (suggested >= 0) { - slot = suggested; - } else if (freeObjectSlots.isEmpty()) { - slot = maxObjectIndex++; - } else { - slot = freeObjectSlots.pop(); - } - break; - case UNREACHABLE: - case VOID: - case TUPLE: - break; - } - if (slot >= 0) { - exprSlots.put(expr, slot); - } - } - return slot; - } - - private boolean checkDone(IrExpr expr) { - if (done.contains(expr)) { - resultSlot = resultSlot(expr); - return true; - } - done.add(expr); - return false; - } - interface BinaryInstructionFactory { Instruction create(int a, int b, int r); }