From d5815b915037caafeeb7f9fc1a80b2d6828907a3 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 23 Jul 2015 19:02:53 +0300 Subject: [PATCH] Refactoring emit API --- .../teavm/model/emit/ComputationEmitter.java | 24 + .../org/teavm/model/emit/ForkEmitter.java | 34 +- .../org/teavm/model/emit/FragmentEmitter.java | 24 + .../java/org/teavm/model/emit/IfEmitter.java | 63 +++ .../org/teavm/model/emit/ProgramEmitter.java | 98 +++- .../org/teavm/model/emit/ValueEmitter.java | 465 +++++++++++++++--- 6 files changed, 594 insertions(+), 114 deletions(-) create mode 100644 teavm-core/src/main/java/org/teavm/model/emit/ComputationEmitter.java create mode 100644 teavm-core/src/main/java/org/teavm/model/emit/FragmentEmitter.java create mode 100644 teavm-core/src/main/java/org/teavm/model/emit/IfEmitter.java diff --git a/teavm-core/src/main/java/org/teavm/model/emit/ComputationEmitter.java b/teavm-core/src/main/java/org/teavm/model/emit/ComputationEmitter.java new file mode 100644 index 000000000..3b7ac4547 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/model/emit/ComputationEmitter.java @@ -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); +} diff --git a/teavm-core/src/main/java/org/teavm/model/emit/ForkEmitter.java b/teavm-core/src/main/java/org/teavm/model/emit/ForkEmitter.java index 5c410e37b..a0d700f32 100644 --- a/teavm-core/src/main/java/org/teavm/model/emit/ForkEmitter.java +++ b/teavm-core/src/main/java/org/teavm/model/emit/ForkEmitter.java @@ -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; } }; } diff --git a/teavm-core/src/main/java/org/teavm/model/emit/FragmentEmitter.java b/teavm-core/src/main/java/org/teavm/model/emit/FragmentEmitter.java new file mode 100644 index 000000000..4a9f7f908 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/model/emit/FragmentEmitter.java @@ -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); +} diff --git a/teavm-core/src/main/java/org/teavm/model/emit/IfEmitter.java b/teavm-core/src/main/java/org/teavm/model/emit/IfEmitter.java new file mode 100644 index 000000000..bc6f16050 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/model/emit/IfEmitter.java @@ -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; + } +} diff --git a/teavm-core/src/main/java/org/teavm/model/emit/ProgramEmitter.java b/teavm-core/src/main/java/org/teavm/model/emit/ProgramEmitter.java index bc74736b4..70db2229f 100644 --- a/teavm-core/src/main/java/org/teavm/model/emit/ProgramEmitter.java +++ b/teavm-core/src/main/java/org/teavm/model/emit/ProgramEmitter.java @@ -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)); + } } diff --git a/teavm-core/src/main/java/org/teavm/model/emit/ValueEmitter.java b/teavm-core/src/main/java/org/teavm/model/emit/ValueEmitter.java index deee5501d..1558b2560 100644 --- a/teavm-core/src/main/java/org/teavm/model/emit/ValueEmitter.java +++ b/teavm-core/src/main/java/org/teavm/model/emit/ValueEmitter.java @@ -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); } }