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
*/
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) {
setThen(block);
return new ForkEmitter() {
@Override public void setThen(BasicBlock block) {
return new ForkEmitter(pe) {
@Override public ForkEmitter setThen(BasicBlock block) {
other.setThen(block);
return this;
}
@Override public void setElse(BasicBlock block) {
@Override public ForkEmitter setElse(BasicBlock block) {
ForkEmitter.this.setElse(block);
other.setElse(block);
return this;
}
};
}
public ForkEmitter or(BasicBlock block, final ForkEmitter other) {
setElse(block);
return new ForkEmitter() {
@Override public void setThen(BasicBlock block) {
return new ForkEmitter(pe) {
@Override public ForkEmitter setThen(BasicBlock block) {
ForkEmitter.this.setThen(block);
other.setThen(block);
return this;
}
@Override public void setElse(BasicBlock block) {
@Override public ForkEmitter setElse(BasicBlock block) {
other.setElse(block);
return this;
}
};
}
public ForkEmitter not() {
return new ForkEmitter() {
@Override public void setThen(BasicBlock block) {
return new ForkEmitter(pe) {
@Override public ForkEmitter setThen(BasicBlock block) {
ForkEmitter.this.setElse(block);
return this;
}
@Override public void setElse(BasicBlock block) {
@Override public ForkEmitter setElse(BasicBlock 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;
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.ConstructArrayInstruction;
import org.teavm.model.instructions.ConstructInstruction;
@ -75,7 +84,7 @@ public final class ProgramEmitter {
insn.setReceiver(var);
insn.setConstant(value);
addInstruction(insn);
return var(var);
return var(var, ValueType.object("java.lang.Class"));
}
public ValueEmitter constant(String value) {
@ -84,7 +93,7 @@ public final class ProgramEmitter {
insn.setReceiver(var);
insn.setConstant(value);
addInstruction(insn);
return var(var);
return var(var, ValueType.object("java.lang.String"));
}
public ValueEmitter constant(int value) {
@ -93,7 +102,7 @@ public final class ProgramEmitter {
insn.setReceiver(var);
insn.setConstant(value);
addInstruction(insn);
return var(var);
return var(var, ValueType.INTEGER);
}
public ValueEmitter constant(long value) {
@ -102,7 +111,7 @@ public final class ProgramEmitter {
insn.setReceiver(var);
insn.setConstant(value);
addInstruction(insn);
return var(var);
return var(var, ValueType.LONG);
}
public ValueEmitter constant(float value) {
@ -111,7 +120,7 @@ public final class ProgramEmitter {
insn.setReceiver(var);
insn.setConstant(value);
addInstruction(insn);
return var(var);
return var(var, ValueType.FLOAT);
}
public ValueEmitter constant(double value) {
@ -120,15 +129,15 @@ public final class ProgramEmitter {
insn.setReceiver(var);
insn.setConstant(value);
addInstruction(insn);
return var(var);
return var(var, ValueType.DOUBLE);
}
public ValueEmitter constantNull() {
public ValueEmitter constantNull(ValueType type) {
Variable var = program.createVariable();
NullConstantInstruction insn = new NullConstantInstruction();
insn.setReceiver(var);
addInstruction(insn);
return var(var);
return var(var, type);
}
public ValueEmitter getField(FieldReference field, ValueType type) {
@ -138,21 +147,33 @@ public final class ProgramEmitter {
insn.setFieldType(type);
insn.setReceiver(var);
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();
insn.setField(field);
insn.setFieldType(type);
insn.setFieldType(value.type);
insn.setValue(value.getVariable());
addInstruction(insn);
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;
if (method.getReturnType() != ValueType.VOID) {
if (resultType != ValueType.VOID) {
result = program.createVariable();
}
InvokeInstruction insn = new InvokeInstruction();
@ -163,25 +184,33 @@ public final class ProgramEmitter {
insn.getArguments().add(arg.variable);
}
addInstruction(insn);
return result != null ? var(result) : null;
return result != null ? var(result, resultType) : null;
}
public ProgramEmitter invokeAndIgnore(MethodReference method, ValueEmitter... arguments) {
invoke(method, arguments);
public ValueEmitter invoke(Class<?> cls, String methodName, Class<?> resultType, ValueEmitter... 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;
}
public ValueEmitter construct(MethodReference method, ValueEmitter... arguments) {
public ValueEmitter construct(String className, ValueEmitter... arguments) {
Variable var = program.createVariable();
ConstructInstruction insn = new ConstructInstruction();
insn.setReceiver(var);
insn.setType(method.getClassName());
insn.setType(className);
addInstruction(insn);
ValueEmitter instance = var(var);
ValueEmitter instance = var(var, ValueType.object(className));
instance.invokeSpecial(method, arguments);
return instance;
}
public ValueEmitter construct(Class<?> cls, ValueEmitter... arguments) {
return construct(cls.getName(), arguments);
}
public ValueEmitter constructArray(ValueType type, ValueEmitter size) {
Variable var = program.createVariable();
ConstructArrayInstruction insn = new ConstructArrayInstruction();
@ -189,7 +218,7 @@ public final class ProgramEmitter {
insn.setSize(size.getVariable());
insn.setItemType(type);
addInstruction(insn);
return var(var);
return var(var, ValueType.arrayOf(type));
}
public ValueEmitter constructArray(ValueType type, int size) {
@ -204,10 +233,11 @@ public final class ProgramEmitter {
return constructArray(ValueType.parse(type), size);
}
public void initClass(String className) {
public ProgramEmitter initClass(String className) {
InitClassInstruction insn = new InitClassInstruction();
insn.setClassName(className);
addInstruction(insn);
return this;
}
public ProgramEmitter jump(BasicBlock block) {
@ -223,12 +253,24 @@ public final class ProgramEmitter {
addInstruction(insn);
}
public ValueEmitter var(Variable var) {
return new ValueEmitter(this, block, var);
public ValueEmitter var(Variable var, ValueType type) {
return new ValueEmitter(this, block, var, type);
}
public ValueEmitter newVar() {
return var(program.createVariable());
public ValueEmitter var(Variable var, Class<?> type) {
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() {
@ -258,4 +300,8 @@ public final class ProgramEmitter {
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.MethodReference;
import org.teavm.model.Phi;
import org.teavm.model.PrimitiveType;
import org.teavm.model.ValueType;
import org.teavm.model.Variable;
import org.teavm.model.instructions.ArrayElementType;
import org.teavm.model.instructions.ArrayLengthInstruction;
import org.teavm.model.instructions.BinaryBranchingCondition;
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.InvokeInstruction;
import org.teavm.model.instructions.IsInstanceInstruction;
import org.teavm.model.instructions.NegateInstruction;
import org.teavm.model.instructions.NumericOperandType;
import org.teavm.model.instructions.PutElementInstruction;
import org.teavm.model.instructions.PutFieldInstruction;
import org.teavm.model.instructions.RaiseInstruction;
import org.teavm.model.instructions.UnwrapArrayInstruction;
/**
@ -56,11 +56,13 @@ public class ValueEmitter {
ProgramEmitter pe;
BasicBlock block;
Variable variable;
ValueType type;
ValueEmitter(ProgramEmitter programEmitter, BasicBlock block, Variable variable) {
ValueEmitter(ProgramEmitter programEmitter, BasicBlock block, Variable variable, ValueType type) {
this.pe = programEmitter;
this.block = block;
this.variable = variable;
this.type = type;
}
public ProgramEmitter getProgramEmitter() {
@ -75,79 +77,310 @@ public class ValueEmitter {
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();
GetFieldInstruction insn = new GetFieldInstruction();
insn.setField(field);
insn.setField(new FieldReference(className, name));
insn.setFieldType(type);
insn.setReceiver(var);
insn.setInstance(variable);
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();
insn.setField(field);
insn.setField(new FieldReference(className, name));
insn.setFieldType(type);
insn.setInstance(variable);
insn.setValue(value.getVariable());
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();
BinaryInstruction insn = new BinaryInstruction(op, type);
insn.setFirstOperand(variable);
insn.setSecondOperand(other.variable);
PrimitiveType common = ((ValueType.Primitive) a.type).getKind();
BinaryInstruction insn = new BinaryInstruction(op, convertToNumeric(common));
insn.setFirstOperand(a.getVariable());
insn.setSecondOperand(b.getVariable());
insn.setReceiver(var);
pe.addInstruction(insn);
return pe.var(var);
return pe.var(var, type);
}
public ValueEmitter add(NumericOperandType type, ValueEmitter other) {
return binary(BinaryOperation.ADD, type, other);
private IntegerSubtype convertToIntegerSubtype(PrimitiveType type) {
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) {
return add(NumericOperandType.INT, other);
private NumericOperandType convertToNumeric(PrimitiveType type) {
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) {
return binary(BinaryOperation.SUBTRACT, type, other);
private PrimitiveType convertNumeric(NumericOperandType type) {
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) {
return sub(NumericOperandType.INT, other);
public ValueEmitter add(ValueEmitter other) {
return binary(BinaryOperation.ADD, other);
}
public ValueEmitter compare(NumericOperandType type, ValueEmitter other) {
return binary(BinaryOperation.COMPARE, type, other);
public ValueEmitter add(int value) {
return binary(BinaryOperation.ADD, pe.constant(value));
}
public ValueEmitter icompare(ValueEmitter other) {
return compare(NumericOperandType.INT, other);
public ValueEmitter sub(ValueEmitter other) {
return binary(BinaryOperation.SUBTRACT, other);
}
public ValueEmitter neg(NumericOperandType type) {
Variable var = pe.getProgram().createVariable();
NegateInstruction insn = new NegateInstruction(type);
insn.setOperand(variable);
insn.setReceiver(var);
return pe.var(var);
public ValueEmitter sub(int value) {
return binary(BinaryOperation.SUBTRACT, pe.constant(value));
}
public ValueEmitter ineg() {
return neg(NumericOperandType.INT);
public ValueEmitter mul(ValueEmitter other) {
return binary(BinaryOperation.MULTIPLY, other);
}
public ValueEmitter invoke(InvocationType type, MethodReference method, ValueEmitter... arguments) {
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);
}
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) {
result = pe.getProgram().createVariable();
}
InvokeInstruction insn = new InvokeInstruction();
insn.setType(type);
insn.setType(invokeType);
insn.setMethod(method);
insn.setInstance(variable);
insn.setReceiver(result);
@ -155,18 +388,54 @@ public class ValueEmitter {
insn.getArguments().add(arg.variable);
}
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) {
return invoke(InvocationType.SPECIAL, method, arguments);
public ValueEmitter invoke(InvocationType invokeType, String name, ValueType resultType,
ValueEmitter... arguments) {
return invoke(invokeType, ((ValueType.Object) type).getClassName(), name, resultType, arguments);
}
public ValueEmitter invokeVirtual(MethodReference method, ValueEmitter... arguments) {
return invoke(InvocationType.VIRTUAL, method, arguments);
public ValueEmitter invokeSpecial(String className, String name, ValueType resultType, ValueEmitter... 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();
Phi phi = new Phi();
phi.setReceiver(var);
@ -179,7 +448,7 @@ public class ValueEmitter {
incoming.setValue(other.variable);
phi.getIncomings().add(incoming);
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) {
@ -187,12 +456,14 @@ public class ValueEmitter {
insn.setFirstOperand(variable);
insn.setSecondOperand(other.variable);
pe.addInstruction(insn);
return new ForkEmitter() {
@Override public void setThen(BasicBlock block) {
return new ForkEmitter(pe) {
@Override public ForkEmitter setThen(BasicBlock block) {
insn.setConsequent(block);
return this;
}
@Override public void setElse(BasicBlock block) {
@Override public ForkEmitter setElse(BasicBlock block) {
insn.setAlternative(block);
return this;
}
};
}
@ -201,12 +472,14 @@ public class ValueEmitter {
final BranchingInstruction insn = new BranchingInstruction(condition);
insn.setOperand(variable);
pe.addInstruction(insn);
return new ForkEmitter() {
@Override public void setThen(BasicBlock block) {
return new ForkEmitter(pe) {
@Override public ForkEmitter setThen(BasicBlock block) {
insn.setConsequent(block);
return this;
}
@Override public void setElse(BasicBlock block) {
@Override public ForkEmitter setElse(BasicBlock block) {
insn.setAlternative(block);
return this;
}
};
}
@ -217,50 +490,88 @@ public class ValueEmitter {
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) {
Variable result = pe.getProgram().createVariable();
CastInstruction insn = new CastInstruction();
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();
CastInstruction insn = new CastInstruction();
insn.setValue(variable);
insn.setReceiver(result);
insn.setTargetType(type);
pe.addInstruction(insn);
return pe.var(result, type);
}
}
public ValueEmitter cast(NumericOperandType to) {
if (!(type instanceof ValueType.Primitive)) {
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.setReceiver(result);
insn.setTargetType(type);
insn.setReceiver(result.getVariable());
pe.addInstruction(insn);
return pe.var(result);
return result;
}
public ValueEmitter cast(NumericOperandType from, NumericOperandType to) {
Variable result = pe.getProgram().createVariable();
CastNumberInstruction insn = new CastNumberInstruction(from, to);
private ValueEmitter castFromInteger(IntegerSubtype subtype) {
CastIntegerInstruction insn = new CastIntegerInstruction(subtype, CastIntegerDirection.TO_INTEGER);
insn.setValue(variable);
insn.setReceiver(result);
ValueEmitter result = pe.newVar(ValueType.INTEGER);
insn.setReceiver(result.getVariable());
pe.addInstruction(insn);
return pe.var(result);
return result;
}
public ValueEmitter cast(IntegerSubtype subtype, CastIntegerDirection dir) {
Variable result = pe.getProgram().createVariable();
CastIntegerInstruction insn = new CastIntegerInstruction(subtype, dir);
private ValueEmitter castToInteger(IntegerSubtype subtype) {
CastIntegerInstruction insn = new CastIntegerInstruction(subtype, CastIntegerDirection.FROM_INTEGER);
insn.setValue(variable);
insn.setReceiver(result);
ValueEmitter result = pe.newVar(ValueType.INTEGER);
insn.setReceiver(result.getVariable());
pe.addInstruction(insn);
return pe.var(result);
}
public ValueEmitter toInteger(IntegerSubtype from) {
return cast(from, CastIntegerDirection.TO_INTEGER);
}
public ValueEmitter fromInteger(IntegerSubtype to) {
return cast(to, CastIntegerDirection.FROM_INTEGER);
return result;
}
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();
GetElementInstruction insn = new GetElementInstruction();
insn.setArray(variable);
insn.setIndex(index.variable);
insn.setReceiver(result);
pe.addInstruction(insn);
return pe.var(result);
return pe.var(result, ((ValueType.Array) type).getItemType());
}
public ValueEmitter getElement(int index) {
@ -279,13 +590,13 @@ public class ValueEmitter {
setElement(pe.constant(index), value);
}
public ValueEmitter unwrapArray(ArrayElementType elementType) {
public ValueEmitter unwrapArray() {
Variable result = pe.getProgram().createVariable();
UnwrapArrayInstruction insn = new UnwrapArrayInstruction(elementType);
insn.setArray(variable);
insn.setReceiver(result);
pe.addInstruction(insn);
return pe.var(result);
return pe.var(result, type);
}
public ValueEmitter arrayLength() {
@ -294,7 +605,7 @@ public class ValueEmitter {
insn.setArray(variable);
insn.setReceiver(result);
pe.addInstruction(insn);
return pe.var(result);
return pe.var(result, ValueType.INTEGER);
}
public ValueEmitter instanceOf(ValueType type) {
@ -304,7 +615,7 @@ public class ValueEmitter {
insn.setReceiver(result);
insn.setType(type);
pe.addInstruction(insn);
return pe.var(result);
return pe.var(result, ValueType.BOOLEAN);
}
public ValueEmitter cloneArray() {
@ -313,6 +624,6 @@ public class ValueEmitter {
insn.setArray(variable);
insn.setReceiver(result);
pe.addInstruction(insn);
return pe.var(result);
return pe.var(result, type);
}
}