mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-27 01:30:35 +08:00
WIP
This commit is contained in:
parent
7f4f1a292e
commit
af3547ab61
@ -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<IrExpr> countMap = new ObjectIntHashMap<>();
|
||||
private ObjectIntMap<IrExpr> 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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(),
|
||||
|
@ -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<IrExpr> pendingConsumers = new ObjectIntHashMap<>();
|
||||
private ObjectIntMap<IrExpr> exprSlots = new ObjectIntHashMap<>();
|
||||
private Set<IrExpr> borrowedSlots = new HashSet<>();
|
||||
private ObjectSet<IrExpr> done = new ObjectHashSet<>();
|
||||
private Set<IrExpr> visited = new HashSet<>();
|
||||
private Map<IrLoopExpr, List<IntConsumer>> loopBreaks = new HashMap<>();
|
||||
private ObjectIntMap<IrLoopExpr> loopHeaders = new ObjectIntHashMap<>();
|
||||
private Map<IrBlockExpr, List<IntConsumer>> 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<IrParameter> parameterSlots,
|
||||
ObjectIntMap<IrVariable> variableSlots
|
||||
ObjectIntMap<IrVariable> 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<IntConsumer> 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<IntConsumer> 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user