mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Refactoring emit API
This commit is contained in:
parent
bda49b95bd
commit
d5815b9150
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
63
teavm-core/src/main/java/org/teavm/model/emit/IfEmitter.java
Normal file
63
teavm-core/src/main/java/org/teavm/model/emit/IfEmitter.java
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user