Refactoring emit API

This commit is contained in:
Alexey Andreev 2015-07-23 19:02:53 +03:00
parent bda49b95bd
commit d5815b9150
6 changed files with 594 additions and 114 deletions

View File

@ -0,0 +1,24 @@
/*
* Copyright 2015 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.model.emit;
/**
*
* @author Alexey Andreev
*/
public interface ComputationEmitter {
ValueEmitter emit(ProgramEmitter pe);
}

View File

@ -22,43 +22,55 @@ import org.teavm.model.BasicBlock;
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public abstract class ForkEmitter { public abstract class ForkEmitter {
public abstract void setThen(BasicBlock block); private ProgramEmitter pe;
public abstract void setElse(BasicBlock block); public ForkEmitter(ProgramEmitter pe) {
this.pe = pe;
}
public abstract ForkEmitter setThen(BasicBlock block);
public abstract ForkEmitter setElse(BasicBlock block);
public ForkEmitter and(BasicBlock block, final ForkEmitter other) { public ForkEmitter and(BasicBlock block, final ForkEmitter other) {
setThen(block); setThen(block);
return new ForkEmitter() { return new ForkEmitter(pe) {
@Override public void setThen(BasicBlock block) { @Override public ForkEmitter setThen(BasicBlock block) {
other.setThen(block); other.setThen(block);
return this;
} }
@Override public void setElse(BasicBlock block) { @Override public ForkEmitter setElse(BasicBlock block) {
ForkEmitter.this.setElse(block); ForkEmitter.this.setElse(block);
other.setElse(block); other.setElse(block);
return this;
} }
}; };
} }
public ForkEmitter or(BasicBlock block, final ForkEmitter other) { public ForkEmitter or(BasicBlock block, final ForkEmitter other) {
setElse(block); setElse(block);
return new ForkEmitter() { return new ForkEmitter(pe) {
@Override public void setThen(BasicBlock block) { @Override public ForkEmitter setThen(BasicBlock block) {
ForkEmitter.this.setThen(block); ForkEmitter.this.setThen(block);
other.setThen(block); other.setThen(block);
return this;
} }
@Override public void setElse(BasicBlock block) { @Override public ForkEmitter setElse(BasicBlock block) {
other.setElse(block); other.setElse(block);
return this;
} }
}; };
} }
public ForkEmitter not() { public ForkEmitter not() {
return new ForkEmitter() { return new ForkEmitter(pe) {
@Override public void setThen(BasicBlock block) { @Override public ForkEmitter setThen(BasicBlock block) {
ForkEmitter.this.setElse(block); ForkEmitter.this.setElse(block);
return this;
} }
@Override public void setElse(BasicBlock block) { @Override public ForkEmitter setElse(BasicBlock block) {
ForkEmitter.this.setThen(block); ForkEmitter.this.setThen(block);
return this;
} }
}; };
} }

View File

@ -0,0 +1,24 @@
/*
* Copyright 2015 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.model.emit;
/**
*
* @author Alexey Andreev
*/
public interface FragmentEmitter {
void emit(ProgramEmitter pe);
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2015 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.model.emit;
import org.teavm.model.BasicBlock;
import org.teavm.model.instructions.BranchingCondition;
/**
*
* @author Alexey Andreev
*/
public class IfEmitter {
private ProgramEmitter pe;
private ForkEmitter fork;
private BasicBlock join;
IfEmitter(ProgramEmitter pe, ForkEmitter fork) {
this.pe = pe;
this.fork = fork;
this.join = pe.createBlock();
}
public IfEmitter and(ComputationEmitter condition) {
BasicBlock block = pe.createBlock();
fork = fork.and(block, condition.emit(pe).fork(BranchingCondition.NOT_EQUAL));
pe.setBlock(join);
return this;
}
public IfEmitter or(ComputationEmitter condition) {
BasicBlock block = pe.createBlock();
fork = fork.or(block, condition.emit(pe).fork(BranchingCondition.NOT_EQUAL));
pe.setBlock(join);
return this;
}
public IfEmitter thenDo(FragmentEmitter fragment) {
fork.setThen(pe.createBlock());
fragment.emit(pe);
pe.jump(join);
return this;
}
public IfEmitter elseDo(FragmentEmitter fragment) {
fork.setThen(pe.createBlock());
fragment.emit(pe);
pe.jump(join);
return this;
}
}

View File

@ -15,7 +15,16 @@
*/ */
package org.teavm.model.emit; package org.teavm.model.emit;
import org.teavm.model.*; import org.teavm.model.BasicBlock;
import org.teavm.model.ClassReader;
import org.teavm.model.FieldReference;
import org.teavm.model.Instruction;
import org.teavm.model.InstructionLocation;
import org.teavm.model.MethodHolder;
import org.teavm.model.Program;
import org.teavm.model.ValueType;
import org.teavm.model.Variable;
import org.teavm.model.instructions.BranchingCondition;
import org.teavm.model.instructions.ClassConstantInstruction; import org.teavm.model.instructions.ClassConstantInstruction;
import org.teavm.model.instructions.ConstructArrayInstruction; import org.teavm.model.instructions.ConstructArrayInstruction;
import org.teavm.model.instructions.ConstructInstruction; import org.teavm.model.instructions.ConstructInstruction;
@ -75,7 +84,7 @@ public final class ProgramEmitter {
insn.setReceiver(var); insn.setReceiver(var);
insn.setConstant(value); insn.setConstant(value);
addInstruction(insn); addInstruction(insn);
return var(var); return var(var, ValueType.object("java.lang.Class"));
} }
public ValueEmitter constant(String value) { public ValueEmitter constant(String value) {
@ -84,7 +93,7 @@ public final class ProgramEmitter {
insn.setReceiver(var); insn.setReceiver(var);
insn.setConstant(value); insn.setConstant(value);
addInstruction(insn); addInstruction(insn);
return var(var); return var(var, ValueType.object("java.lang.String"));
} }
public ValueEmitter constant(int value) { public ValueEmitter constant(int value) {
@ -93,7 +102,7 @@ public final class ProgramEmitter {
insn.setReceiver(var); insn.setReceiver(var);
insn.setConstant(value); insn.setConstant(value);
addInstruction(insn); addInstruction(insn);
return var(var); return var(var, ValueType.INTEGER);
} }
public ValueEmitter constant(long value) { public ValueEmitter constant(long value) {
@ -102,7 +111,7 @@ public final class ProgramEmitter {
insn.setReceiver(var); insn.setReceiver(var);
insn.setConstant(value); insn.setConstant(value);
addInstruction(insn); addInstruction(insn);
return var(var); return var(var, ValueType.LONG);
} }
public ValueEmitter constant(float value) { public ValueEmitter constant(float value) {
@ -111,7 +120,7 @@ public final class ProgramEmitter {
insn.setReceiver(var); insn.setReceiver(var);
insn.setConstant(value); insn.setConstant(value);
addInstruction(insn); addInstruction(insn);
return var(var); return var(var, ValueType.FLOAT);
} }
public ValueEmitter constant(double value) { public ValueEmitter constant(double value) {
@ -120,15 +129,15 @@ public final class ProgramEmitter {
insn.setReceiver(var); insn.setReceiver(var);
insn.setConstant(value); insn.setConstant(value);
addInstruction(insn); addInstruction(insn);
return var(var); return var(var, ValueType.DOUBLE);
} }
public ValueEmitter constantNull() { public ValueEmitter constantNull(ValueType type) {
Variable var = program.createVariable(); Variable var = program.createVariable();
NullConstantInstruction insn = new NullConstantInstruction(); NullConstantInstruction insn = new NullConstantInstruction();
insn.setReceiver(var); insn.setReceiver(var);
addInstruction(insn); addInstruction(insn);
return var(var); return var(var, type);
} }
public ValueEmitter getField(FieldReference field, ValueType type) { public ValueEmitter getField(FieldReference field, ValueType type) {
@ -138,21 +147,33 @@ public final class ProgramEmitter {
insn.setFieldType(type); insn.setFieldType(type);
insn.setReceiver(var); insn.setReceiver(var);
addInstruction(insn); addInstruction(insn);
return var(var); return var(var, type);
} }
public ProgramEmitter setField(FieldReference field, ValueType type, ValueEmitter value) { public ValueEmitter getField(String className, String fieldName, ValueType type) {
return getField(new FieldReference(className, fieldName), type);
}
public ValueEmitter getField(Class<?> cls, String fieldName, Class<?> type) {
return getField(cls.getName(), fieldName, ValueType.parse(type));
}
public ProgramEmitter setField(FieldReference field, ValueEmitter value) {
PutFieldInstruction insn = new PutFieldInstruction(); PutFieldInstruction insn = new PutFieldInstruction();
insn.setField(field); insn.setField(field);
insn.setFieldType(type); insn.setFieldType(value.type);
insn.setValue(value.getVariable()); insn.setValue(value.getVariable());
addInstruction(insn); addInstruction(insn);
return this; return this;
} }
public ValueEmitter invoke(MethodReference method, ValueEmitter... arguments) { public ProgramEmitter setField(String className, String fieldName, ValueEmitter value) {
return setField(new FieldReference(className, fieldName), value);
}
public ValueEmitter invoke(String className, String methodName, ValueType resultType, ValueEmitter... arguments) {
Variable result = null; Variable result = null;
if (method.getReturnType() != ValueType.VOID) { if (resultType != ValueType.VOID) {
result = program.createVariable(); result = program.createVariable();
} }
InvokeInstruction insn = new InvokeInstruction(); InvokeInstruction insn = new InvokeInstruction();
@ -163,25 +184,33 @@ public final class ProgramEmitter {
insn.getArguments().add(arg.variable); insn.getArguments().add(arg.variable);
} }
addInstruction(insn); addInstruction(insn);
return result != null ? var(result) : null; return result != null ? var(result, resultType) : null;
} }
public ProgramEmitter invokeAndIgnore(MethodReference method, ValueEmitter... arguments) { public ValueEmitter invoke(Class<?> cls, String methodName, Class<?> resultType, ValueEmitter... arguments) {
invoke(method, arguments); return invoke(cls.getName(), methodName, ValueType.parse(resultType), arguments);
}
public ProgramEmitter invoke(String className, String methodName, ValueEmitter... arguments) {
invoke(className, methodName, ValueType.VOID, arguments);
return this; return this;
} }
public ValueEmitter construct(MethodReference method, ValueEmitter... arguments) { public ValueEmitter construct(String className, ValueEmitter... arguments) {
Variable var = program.createVariable(); Variable var = program.createVariable();
ConstructInstruction insn = new ConstructInstruction(); ConstructInstruction insn = new ConstructInstruction();
insn.setReceiver(var); insn.setReceiver(var);
insn.setType(method.getClassName()); insn.setType(className);
addInstruction(insn); addInstruction(insn);
ValueEmitter instance = var(var); ValueEmitter instance = var(var, ValueType.object(className));
instance.invokeSpecial(method, arguments); instance.invokeSpecial(method, arguments);
return instance; return instance;
} }
public ValueEmitter construct(Class<?> cls, ValueEmitter... arguments) {
return construct(cls.getName(), arguments);
}
public ValueEmitter constructArray(ValueType type, ValueEmitter size) { public ValueEmitter constructArray(ValueType type, ValueEmitter size) {
Variable var = program.createVariable(); Variable var = program.createVariable();
ConstructArrayInstruction insn = new ConstructArrayInstruction(); ConstructArrayInstruction insn = new ConstructArrayInstruction();
@ -189,7 +218,7 @@ public final class ProgramEmitter {
insn.setSize(size.getVariable()); insn.setSize(size.getVariable());
insn.setItemType(type); insn.setItemType(type);
addInstruction(insn); addInstruction(insn);
return var(var); return var(var, ValueType.arrayOf(type));
} }
public ValueEmitter constructArray(ValueType type, int size) { public ValueEmitter constructArray(ValueType type, int size) {
@ -204,10 +233,11 @@ public final class ProgramEmitter {
return constructArray(ValueType.parse(type), size); return constructArray(ValueType.parse(type), size);
} }
public void initClass(String className) { public ProgramEmitter initClass(String className) {
InitClassInstruction insn = new InitClassInstruction(); InitClassInstruction insn = new InitClassInstruction();
insn.setClassName(className); insn.setClassName(className);
addInstruction(insn); addInstruction(insn);
return this;
} }
public ProgramEmitter jump(BasicBlock block) { public ProgramEmitter jump(BasicBlock block) {
@ -223,12 +253,24 @@ public final class ProgramEmitter {
addInstruction(insn); addInstruction(insn);
} }
public ValueEmitter var(Variable var) { public ValueEmitter var(Variable var, ValueType type) {
return new ValueEmitter(this, block, var); return new ValueEmitter(this, block, var, type);
} }
public ValueEmitter newVar() { public ValueEmitter var(Variable var, Class<?> type) {
return var(program.createVariable()); return var(var, ValueType.parse(type));
}
public ValueEmitter newVar(ValueType type) {
return var(program.createVariable(), type);
}
public ValueEmitter newVar(ClassReader cls) {
return var(program.createVariable(), ValueType.object(cls.getName()));
}
public ValueEmitter newVar(Class<?> type) {
return var(program.createVariable(), type);
} }
public InstructionLocation getCurrentLocation() { public InstructionLocation getCurrentLocation() {
@ -258,4 +300,8 @@ public final class ProgramEmitter {
return new ProgramEmitter(program, block); return new ProgramEmitter(program, block);
} }
public IfEmitter when(ComputationEmitter condition) {
return new IfEmitter(this, condition.emit(this).fork(BranchingCondition.NOT_EQUAL));
}
} }

View File

@ -20,9 +20,9 @@ import org.teavm.model.FieldReference;
import org.teavm.model.Incoming; import org.teavm.model.Incoming;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.Phi; import org.teavm.model.Phi;
import org.teavm.model.PrimitiveType;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
import org.teavm.model.Variable; import org.teavm.model.Variable;
import org.teavm.model.instructions.ArrayElementType;
import org.teavm.model.instructions.ArrayLengthInstruction; import org.teavm.model.instructions.ArrayLengthInstruction;
import org.teavm.model.instructions.BinaryBranchingCondition; import org.teavm.model.instructions.BinaryBranchingCondition;
import org.teavm.model.instructions.BinaryBranchingInstruction; import org.teavm.model.instructions.BinaryBranchingInstruction;
@ -42,10 +42,10 @@ import org.teavm.model.instructions.IntegerSubtype;
import org.teavm.model.instructions.InvocationType; import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.IsInstanceInstruction; import org.teavm.model.instructions.IsInstanceInstruction;
import org.teavm.model.instructions.NegateInstruction;
import org.teavm.model.instructions.NumericOperandType; import org.teavm.model.instructions.NumericOperandType;
import org.teavm.model.instructions.PutElementInstruction; import org.teavm.model.instructions.PutElementInstruction;
import org.teavm.model.instructions.PutFieldInstruction; import org.teavm.model.instructions.PutFieldInstruction;
import org.teavm.model.instructions.RaiseInstruction;
import org.teavm.model.instructions.UnwrapArrayInstruction; import org.teavm.model.instructions.UnwrapArrayInstruction;
/** /**
@ -56,11 +56,13 @@ public class ValueEmitter {
ProgramEmitter pe; ProgramEmitter pe;
BasicBlock block; BasicBlock block;
Variable variable; Variable variable;
ValueType type;
ValueEmitter(ProgramEmitter programEmitter, BasicBlock block, Variable variable) { ValueEmitter(ProgramEmitter programEmitter, BasicBlock block, Variable variable, ValueType type) {
this.pe = programEmitter; this.pe = programEmitter;
this.block = block; this.block = block;
this.variable = variable; this.variable = variable;
this.type = type;
} }
public ProgramEmitter getProgramEmitter() { public ProgramEmitter getProgramEmitter() {
@ -75,79 +77,310 @@ public class ValueEmitter {
return variable; return variable;
} }
public ValueEmitter getField(FieldReference field, ValueType type) { public ValueType getType() {
return type;
}
public ValueEmitter getField(String name, ValueType type) {
if (!(type instanceof ValueType.Object)) {
throw new IllegalStateException("Can't get field of non-object type: " + type);
}
String className = ((ValueType.Object) type).getClassName();
Variable var = pe.getProgram().createVariable(); Variable var = pe.getProgram().createVariable();
GetFieldInstruction insn = new GetFieldInstruction(); GetFieldInstruction insn = new GetFieldInstruction();
insn.setField(field); insn.setField(new FieldReference(className, name));
insn.setFieldType(type); insn.setFieldType(type);
insn.setReceiver(var); insn.setReceiver(var);
insn.setInstance(variable); insn.setInstance(variable);
pe.addInstruction(insn); pe.addInstruction(insn);
return pe.var(var); return pe.var(var, type);
} }
public void setField(FieldReference field, ValueType type, ValueEmitter value) { public ValueEmitter getField(String name, Class<?> type) {
return getField(name, ValueType.parse(type));
}
public void setField(String name, ValueEmitter value) {
if (!(type instanceof ValueType.Object)) {
throw new IllegalStateException("Can't get field of non-object type: " + type);
}
String className = ((ValueType.Object) type).getClassName();
PutFieldInstruction insn = new PutFieldInstruction(); PutFieldInstruction insn = new PutFieldInstruction();
insn.setField(field); insn.setField(new FieldReference(className, name));
insn.setFieldType(type); insn.setFieldType(type);
insn.setInstance(variable); insn.setInstance(variable);
insn.setValue(value.getVariable()); insn.setValue(value.getVariable());
pe.addInstruction(insn); pe.addInstruction(insn);
} }
public ValueEmitter binary(BinaryOperation op, NumericOperandType type, ValueEmitter other) { static class Pair {
ValueEmitter first;
ValueEmitter second;
public Pair(ValueEmitter first, ValueEmitter second) {
this.first = first;
this.second = second;
}
}
private Pair commonNumeric(ValueEmitter other) {
if (!(type instanceof ValueType.Primitive)) {
throw new IllegalArgumentException("First argument is not a primitive: " + type);
}
if (!(other.type instanceof ValueType.Primitive)) {
throw new IllegalArgumentException("First argument is not a primitive: " + other.type);
}
PrimitiveType firstType = ((ValueType.Primitive) type).getKind();
PrimitiveType secondType = ((ValueType.Primitive) other.type).getKind();
if (firstType == PrimitiveType.BOOLEAN) {
throw new IllegalArgumentException("First argument is not numeric: " + type);
}
if (secondType == PrimitiveType.BOOLEAN) {
throw new IllegalArgumentException("Second argument is not numeric: " + other.type);
}
ValueEmitter a = this;
ValueEmitter b = other;
IntegerSubtype firstSubtype = convertToIntegerSubtype(firstType);
if (firstSubtype != null) {
a = castFromInteger(firstSubtype);
firstType = PrimitiveType.INTEGER;
}
IntegerSubtype secondSubtype = convertToIntegerSubtype(secondType);
if (secondSubtype != null) {
b = castFromInteger(secondSubtype);
secondType = PrimitiveType.INTEGER;
}
NumericOperandType firstNumeric = convertToNumeric(firstType);
NumericOperandType secondNumeric = convertToNumeric(secondType);
int commonIndex = Math.max(firstNumeric.ordinal(), secondNumeric.ordinal());
NumericOperandType common = NumericOperandType.values()[commonIndex];
ValueType commonType = ValueType.primitive(convertNumeric(common));
if (firstNumeric != common) {
CastNumberInstruction insn = new CastNumberInstruction(firstNumeric, common);
insn.setValue(a.getVariable());
a = pe.newVar(commonType);
insn.setReceiver(a.getVariable());
pe.addInstruction(insn);
}
if (secondNumeric != common) {
CastNumberInstruction insn = new CastNumberInstruction(secondNumeric, common);
insn.setValue(b.getVariable());
b = pe.newVar(commonType);
insn.setReceiver(b.getVariable());
pe.addInstruction(insn);
}
return new Pair(a, b);
}
private ValueEmitter binary(BinaryOperation op, ValueEmitter other) {
Pair pair = commonNumeric(other);
return binaryOp(op, pair.first, pair.second, pair.first.type);
}
private ValueEmitter binaryOp(BinaryOperation op, ValueEmitter a, ValueEmitter b, ValueType type) {
Variable var = pe.getProgram().createVariable(); Variable var = pe.getProgram().createVariable();
BinaryInstruction insn = new BinaryInstruction(op, type); PrimitiveType common = ((ValueType.Primitive) a.type).getKind();
insn.setFirstOperand(variable);
insn.setSecondOperand(other.variable); BinaryInstruction insn = new BinaryInstruction(op, convertToNumeric(common));
insn.setFirstOperand(a.getVariable());
insn.setSecondOperand(b.getVariable());
insn.setReceiver(var); insn.setReceiver(var);
pe.addInstruction(insn); pe.addInstruction(insn);
return pe.var(var); return pe.var(var, type);
} }
public ValueEmitter add(NumericOperandType type, ValueEmitter other) { private IntegerSubtype convertToIntegerSubtype(PrimitiveType type) {
return binary(BinaryOperation.ADD, type, other); switch (type) {
case BYTE:
return IntegerSubtype.BYTE;
case SHORT:
return IntegerSubtype.SHORT;
case CHARACTER:
return IntegerSubtype.CHARACTER;
default:
break;
}
return null;
} }
public ValueEmitter iadd(ValueEmitter other) { private NumericOperandType convertToNumeric(PrimitiveType type) {
return add(NumericOperandType.INT, other); switch (type) {
case BYTE:
case SHORT:
case CHARACTER:
case INTEGER:
return NumericOperandType.INT;
case LONG:
return NumericOperandType.LONG;
case FLOAT:
return NumericOperandType.FLOAT;
case DOUBLE:
return NumericOperandType.DOUBLE;
default:
break;
}
throw new AssertionError("Unexpected type: " + type);
} }
public ValueEmitter sub(NumericOperandType type, ValueEmitter other) { private PrimitiveType convertNumeric(NumericOperandType type) {
return binary(BinaryOperation.SUBTRACT, type, other); switch (type) {
case INT:
return PrimitiveType.INTEGER;
case LONG:
return PrimitiveType.LONG;
case FLOAT:
return PrimitiveType.FLOAT;
case DOUBLE:
return PrimitiveType.DOUBLE;
default:
break;
}
throw new AssertionError("Unknown type: " + type);
} }
public ValueEmitter isub(ValueEmitter other) { public ValueEmitter add(ValueEmitter other) {
return sub(NumericOperandType.INT, other); return binary(BinaryOperation.ADD, other);
} }
public ValueEmitter compare(NumericOperandType type, ValueEmitter other) { public ValueEmitter add(int value) {
return binary(BinaryOperation.COMPARE, type, other); return binary(BinaryOperation.ADD, pe.constant(value));
} }
public ValueEmitter icompare(ValueEmitter other) { public ValueEmitter sub(ValueEmitter other) {
return compare(NumericOperandType.INT, other); return binary(BinaryOperation.SUBTRACT, other);
} }
public ValueEmitter neg(NumericOperandType type) { public ValueEmitter sub(int value) {
Variable var = pe.getProgram().createVariable(); return binary(BinaryOperation.SUBTRACT, pe.constant(value));
NegateInstruction insn = new NegateInstruction(type);
insn.setOperand(variable);
insn.setReceiver(var);
return pe.var(var);
} }
public ValueEmitter ineg() { public ValueEmitter mul(ValueEmitter other) {
return neg(NumericOperandType.INT); return binary(BinaryOperation.MULTIPLY, other);
}
public ValueEmitter mul(int value) {
return binary(BinaryOperation.MULTIPLY, pe.constant(value));
}
public ValueEmitter div(ValueEmitter other) {
return binary(BinaryOperation.DIVIDE, other);
}
public ValueEmitter div(int value) {
return binary(BinaryOperation.DIVIDE, pe.constant(value));
}
public ValueEmitter rem(ValueEmitter other) {
return binary(BinaryOperation.MODULO, other);
}
public ValueEmitter rem(int value) {
return binary(BinaryOperation.MODULO, pe.constant(value));
}
public ValueEmitter compareTo(ValueEmitter other) {
Pair pair = commonNumeric(other);
return binaryOp(BinaryOperation.COMPARE, pair.first, pair.second, ValueType.INTEGER);
}
public ValueEmitter compareTo(int value) {
return compareTo(pe.constant(value));
}
private ValueEmitter logical(BinaryOperation op, ValueEmitter other) {
Pair pair = commonNumeric(other);
PrimitiveType common = ((ValueType.Primitive) pair.first.type).getKind();
checkInteger(common);
return binaryOp(op, pair.first, pair.second, pair.first.type);
}
public ValueEmitter bitAnd(ValueEmitter other) {
return logical(BinaryOperation.AND, other);
}
private void checkInteger(PrimitiveType common) {
switch (common) {
case FLOAT:
case DOUBLE:
throw new IllegalArgumentException("Can't perform bitwise operation between non-integers");
default:
break;
}
}
public ValueEmitter bitAnd(int value) {
return bitAnd(pe.constant(value));
}
public ValueEmitter bitOr(ValueEmitter other) {
return logical(BinaryOperation.OR, other);
}
public ValueEmitter bitOr(int value) {
return bitOr(pe.constant(value));
}
public ValueEmitter bitXor(ValueEmitter other) {
return logical(BinaryOperation.XOR, other);
}
public ValueEmitter bitXor(int value) {
return bitXor(pe.constant(value));
}
public ValueEmitter shl(ValueEmitter other) {
return binary(BinaryOperation.SHIFT_LEFT, other);
}
public ValueEmitter shl(int value) {
return binary(BinaryOperation.SHIFT_LEFT, pe.constant(value));
}
public ValueEmitter shr(ValueEmitter other) {
return binary(BinaryOperation.SHIFT_RIGHT, other);
}
public ValueEmitter shr(int value) {
return binary(BinaryOperation.SHIFT_RIGHT, pe.constant(value));
}
public ValueEmitter shru(ValueEmitter other) {
return binary(BinaryOperation.SHIFT_RIGHT_UNSIGNED, other);
}
public ValueEmitter shru(int value) {
return binary(BinaryOperation.SHIFT_RIGHT_UNSIGNED, pe.constant(value));
}
public ValueEmitter invoke(InvocationType invokeType, String className, String name, ValueType resultType,
ValueEmitter... arguments) {
if (!(type instanceof ValueType.Object)) {
throw new IllegalStateException("Can't invoke method on non-object type: " + type);
} }
public ValueEmitter invoke(InvocationType type, MethodReference method, ValueEmitter... arguments) {
Variable result = null; Variable result = null;
String className = ((ValueType.Object) type).getClassName();
ValueType[] signature = new ValueType[arguments.length + 1];
for (int i = 0; i < arguments.length; ++i) {
signature[i] = arguments[i].type;
}
signature[arguments.length] = resultType;
MethodReference method = new MethodReference(className, name, signature);
if (method.getReturnType() != ValueType.VOID) { if (method.getReturnType() != ValueType.VOID) {
result = pe.getProgram().createVariable(); result = pe.getProgram().createVariable();
} }
InvokeInstruction insn = new InvokeInstruction(); InvokeInstruction insn = new InvokeInstruction();
insn.setType(type); insn.setType(invokeType);
insn.setMethod(method); insn.setMethod(method);
insn.setInstance(variable); insn.setInstance(variable);
insn.setReceiver(result); insn.setReceiver(result);
@ -155,18 +388,54 @@ public class ValueEmitter {
insn.getArguments().add(arg.variable); insn.getArguments().add(arg.variable);
} }
pe.addInstruction(insn); pe.addInstruction(insn);
return result != null ? pe.var(result) : null; return result != null ? pe.var(result, resultType) : null;
} }
public ValueEmitter invokeSpecial(MethodReference method, ValueEmitter... arguments) { public ValueEmitter invoke(InvocationType invokeType, String name, ValueType resultType,
return invoke(InvocationType.SPECIAL, method, arguments); ValueEmitter... arguments) {
return invoke(invokeType, ((ValueType.Object) type).getClassName(), name, resultType, arguments);
} }
public ValueEmitter invokeVirtual(MethodReference method, ValueEmitter... arguments) { public ValueEmitter invokeSpecial(String className, String name, ValueType resultType, ValueEmitter... arguments) {
return invoke(InvocationType.VIRTUAL, method, arguments); return invoke(InvocationType.SPECIAL, className, name, resultType, arguments);
} }
public ValueEmitter join(BasicBlock block, ValueEmitter other, BasicBlock otherBlock) { public ValueEmitter invokeSpecial(String name, ValueType resultType, ValueEmitter... arguments) {
return invoke(InvocationType.SPECIAL, name, resultType, arguments);
}
public ValueEmitter invokeSpecial(String name, Class<?> resultType, ValueEmitter... arguments) {
return invoke(InvocationType.SPECIAL, name, ValueType.parse(resultType), arguments);
}
public ProgramEmitter invokeSpecial(String className, String name, ValueEmitter... arguments) {
invokeSpecial(className, name, ValueType.VOID, arguments);
return pe;
}
public ProgramEmitter invokeSpecial(Class<?> cls, String name, ValueEmitter... arguments) {
invokeSpecial(cls.getName(), name, ValueType.VOID, arguments);
return pe;
}
public ProgramEmitter invokeSpecial(String name, ValueEmitter... arguments) {
invokeSpecial(name, ValueType.VOID, arguments);
return pe;
}
public ValueEmitter invokeVirtual(String name, ValueType resultType, ValueEmitter... arguments) {
return invoke(InvocationType.VIRTUAL, name, resultType, arguments);
}
public ValueEmitter invokeVirtual(String name, Class<?> resultType, ValueEmitter... arguments) {
return invoke(InvocationType.VIRTUAL, name, ValueType.parse(resultType), arguments);
}
public void invokeVirtual(String name, ValueEmitter... arguments) {
invokeVirtual(name, ValueType.VOID, arguments);
}
public ValueEmitter join(BasicBlock block, ValueEmitter other, BasicBlock otherBlock, ValueType type) {
Variable var = pe.getProgram().createVariable(); Variable var = pe.getProgram().createVariable();
Phi phi = new Phi(); Phi phi = new Phi();
phi.setReceiver(var); phi.setReceiver(var);
@ -179,7 +448,7 @@ public class ValueEmitter {
incoming.setValue(other.variable); incoming.setValue(other.variable);
phi.getIncomings().add(incoming); phi.getIncomings().add(incoming);
pe.getBlock().getPhis().add(phi); pe.getBlock().getPhis().add(phi);
return new ValueEmitter(pe, pe.getBlock(), var); return new ValueEmitter(pe, pe.getBlock(), var, type);
} }
public ForkEmitter fork(BinaryBranchingCondition condition, ValueEmitter other) { public ForkEmitter fork(BinaryBranchingCondition condition, ValueEmitter other) {
@ -187,12 +456,14 @@ public class ValueEmitter {
insn.setFirstOperand(variable); insn.setFirstOperand(variable);
insn.setSecondOperand(other.variable); insn.setSecondOperand(other.variable);
pe.addInstruction(insn); pe.addInstruction(insn);
return new ForkEmitter() { return new ForkEmitter(pe) {
@Override public void setThen(BasicBlock block) { @Override public ForkEmitter setThen(BasicBlock block) {
insn.setConsequent(block); insn.setConsequent(block);
return this;
} }
@Override public void setElse(BasicBlock block) { @Override public ForkEmitter setElse(BasicBlock block) {
insn.setAlternative(block); insn.setAlternative(block);
return this;
} }
}; };
} }
@ -201,12 +472,14 @@ public class ValueEmitter {
final BranchingInstruction insn = new BranchingInstruction(condition); final BranchingInstruction insn = new BranchingInstruction(condition);
insn.setOperand(variable); insn.setOperand(variable);
pe.addInstruction(insn); pe.addInstruction(insn);
return new ForkEmitter() { return new ForkEmitter(pe) {
@Override public void setThen(BasicBlock block) { @Override public ForkEmitter setThen(BasicBlock block) {
insn.setConsequent(block); insn.setConsequent(block);
return this;
} }
@Override public void setElse(BasicBlock block) { @Override public ForkEmitter setElse(BasicBlock block) {
insn.setAlternative(block); insn.setAlternative(block);
return this;
} }
}; };
} }
@ -217,50 +490,88 @@ public class ValueEmitter {
pe.addInstruction(insn); pe.addInstruction(insn);
} }
public void raise() {
RaiseInstruction insn = new RaiseInstruction();
insn.setException(variable);
pe.addInstruction(insn);
}
public ValueEmitter cast(Class<?> type) {
return cast(ValueType.parse(type));
}
public ValueEmitter cast(ValueType type) { public ValueEmitter cast(ValueType type) {
if (type.equals(this.type)) {
return this;
}
if (type instanceof ValueType.Primitive) {
} else {
if (this.type instanceof ValueType.Primitive) {
throw new IllegalStateException("Can't convert " + this.type + " to " + type);
}
Variable result = pe.getProgram().createVariable(); Variable result = pe.getProgram().createVariable();
CastInstruction insn = new CastInstruction(); CastInstruction insn = new CastInstruction();
insn.setValue(variable); insn.setValue(variable);
insn.setReceiver(result); insn.setReceiver(result);
insn.setTargetType(type); insn.setTargetType(type);
pe.addInstruction(insn); pe.addInstruction(insn);
return pe.var(result); return pe.var(result, type);
}
} }
public ValueEmitter cast(NumericOperandType from, NumericOperandType to) { public ValueEmitter cast(NumericOperandType to) {
Variable result = pe.getProgram().createVariable(); if (!(type instanceof ValueType.Primitive)) {
CastNumberInstruction insn = new CastNumberInstruction(from, to); throw new IllegalStateException("Can't cast non-primitive type: " + type);
}
ValueEmitter value = this;
PrimitiveType kind = ((ValueType.Primitive) type).getKind();
IntegerSubtype subtype = convertToIntegerSubtype(kind);
if (subtype != null) {
value = value.castFromInteger(subtype);
kind = PrimitiveType.INTEGER;
}
ValueEmitter result = pe.newVar(ValueType.INTEGER);
CastNumberInstruction insn = new CastNumberInstruction(convertToNumeric(kind), to);
insn.setValue(variable); insn.setValue(variable);
insn.setReceiver(result); insn.setReceiver(result.getVariable());
pe.addInstruction(insn); pe.addInstruction(insn);
return pe.var(result);
return result;
} }
public ValueEmitter cast(IntegerSubtype subtype, CastIntegerDirection dir) { private ValueEmitter castFromInteger(IntegerSubtype subtype) {
Variable result = pe.getProgram().createVariable(); CastIntegerInstruction insn = new CastIntegerInstruction(subtype, CastIntegerDirection.TO_INTEGER);
CastIntegerInstruction insn = new CastIntegerInstruction(subtype, dir);
insn.setValue(variable); insn.setValue(variable);
insn.setReceiver(result); ValueEmitter result = pe.newVar(ValueType.INTEGER);
insn.setReceiver(result.getVariable());
pe.addInstruction(insn); pe.addInstruction(insn);
return pe.var(result); return result;
} }
public ValueEmitter toInteger(IntegerSubtype from) { private ValueEmitter castToInteger(IntegerSubtype subtype) {
return cast(from, CastIntegerDirection.TO_INTEGER); CastIntegerInstruction insn = new CastIntegerInstruction(subtype, CastIntegerDirection.FROM_INTEGER);
} insn.setValue(variable);
ValueEmitter result = pe.newVar(ValueType.INTEGER);
public ValueEmitter fromInteger(IntegerSubtype to) { insn.setReceiver(result.getVariable());
return cast(to, CastIntegerDirection.FROM_INTEGER); pe.addInstruction(insn);
return result;
} }
public ValueEmitter getElement(ValueEmitter index) { public ValueEmitter getElement(ValueEmitter index) {
if (!(type instanceof ValueType.Array)) {
throw new IllegalArgumentException("Can't get element of non-array type: " + type);
}
Variable result = pe.getProgram().createVariable(); Variable result = pe.getProgram().createVariable();
GetElementInstruction insn = new GetElementInstruction(); GetElementInstruction insn = new GetElementInstruction();
insn.setArray(variable); insn.setArray(variable);
insn.setIndex(index.variable); insn.setIndex(index.variable);
insn.setReceiver(result); insn.setReceiver(result);
pe.addInstruction(insn); pe.addInstruction(insn);
return pe.var(result); return pe.var(result, ((ValueType.Array) type).getItemType());
} }
public ValueEmitter getElement(int index) { public ValueEmitter getElement(int index) {
@ -279,13 +590,13 @@ public class ValueEmitter {
setElement(pe.constant(index), value); setElement(pe.constant(index), value);
} }
public ValueEmitter unwrapArray(ArrayElementType elementType) { public ValueEmitter unwrapArray() {
Variable result = pe.getProgram().createVariable(); Variable result = pe.getProgram().createVariable();
UnwrapArrayInstruction insn = new UnwrapArrayInstruction(elementType); UnwrapArrayInstruction insn = new UnwrapArrayInstruction(elementType);
insn.setArray(variable); insn.setArray(variable);
insn.setReceiver(result); insn.setReceiver(result);
pe.addInstruction(insn); pe.addInstruction(insn);
return pe.var(result); return pe.var(result, type);
} }
public ValueEmitter arrayLength() { public ValueEmitter arrayLength() {
@ -294,7 +605,7 @@ public class ValueEmitter {
insn.setArray(variable); insn.setArray(variable);
insn.setReceiver(result); insn.setReceiver(result);
pe.addInstruction(insn); pe.addInstruction(insn);
return pe.var(result); return pe.var(result, ValueType.INTEGER);
} }
public ValueEmitter instanceOf(ValueType type) { public ValueEmitter instanceOf(ValueType type) {
@ -304,7 +615,7 @@ public class ValueEmitter {
insn.setReceiver(result); insn.setReceiver(result);
insn.setType(type); insn.setType(type);
pe.addInstruction(insn); pe.addInstruction(insn);
return pe.var(result); return pe.var(result, ValueType.BOOLEAN);
} }
public ValueEmitter cloneArray() { public ValueEmitter cloneArray() {
@ -313,6 +624,6 @@ public class ValueEmitter {
insn.setArray(variable); insn.setArray(variable);
insn.setReceiver(result); insn.setReceiver(result);
pe.addInstruction(insn); pe.addInstruction(insn);
return pe.var(result); return pe.var(result, type);
} }
} }