Improving emit API

This commit is contained in:
Alexey Andreev 2015-07-27 17:46:55 +03:00
parent 00a751ef13
commit 3eea8da7fa
12 changed files with 414 additions and 124 deletions

View File

@ -44,12 +44,14 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
}
int capturedVarCount = callSite.getCalledMethod().parameterCount();
MethodHolder ctor = createConstructor(implementor, Arrays.copyOfRange(invokedType, 0, capturedVarCount));
createBridge(implementor, callSite.getCalledMethod().getName(), instantiatedMethodType, samMethodType);
MethodHolder ctor = createConstructor(classSource, implementor,
Arrays.copyOfRange(invokedType, 0, capturedVarCount));
createBridge(classSource, implementor, callSite.getCalledMethod().getName(), instantiatedMethodType,
samMethodType);
MethodHolder worker = new MethodHolder(callSite.getCalledMethod().getName(), instantiatedMethodType);
worker.setLevel(AccessLevel.PUBLIC);
ProgramEmitter pe = ProgramEmitter.create(worker);
ProgramEmitter pe = ProgramEmitter.create(worker, callSite.getAgent().getClassSource());
ValueEmitter thisVar = pe.var(0, implementor);
ValueEmitter[] arguments = new ValueEmitter[instantiatedMethodType.length - 1];
for (int i = 0; i < arguments.length; ++i) {
@ -199,13 +201,13 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
}
}
private MethodHolder createConstructor(ClassHolder implementor, ValueType[] types) {
private MethodHolder createConstructor(ClassReaderSource classSource, ClassHolder implementor, ValueType[] types) {
ValueType[] signature = Arrays.copyOf(types, types.length + 1);
signature[types.length] = ValueType.VOID;
MethodHolder ctor = new MethodHolder("<init>", signature);
ctor.setLevel(AccessLevel.PUBLIC);
ProgramEmitter pe = ProgramEmitter.create(ctor);
ProgramEmitter pe = ProgramEmitter.create(ctor, classSource);
ValueEmitter thisVar = pe.var(0, implementor);
thisVar.invokeSpecial(implementor.getParent(), "<init>");
@ -222,7 +224,8 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
return ctor;
}
private void createBridge(ClassHolder implementor, String name, ValueType[] types, ValueType[] bridgeTypes) {
private void createBridge(ClassReaderSource classSource, ClassHolder implementor, String name, ValueType[] types,
ValueType[] bridgeTypes) {
if (Arrays.equals(types, bridgeTypes)) {
return;
}
@ -230,7 +233,7 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
MethodHolder bridge = new MethodHolder(name, bridgeTypes);
bridge.setLevel(AccessLevel.PUBLIC);
bridge.getModifiers().add(ElementModifier.BRIDGE);
ProgramEmitter pe = ProgramEmitter.create(bridge);
ProgramEmitter pe = ProgramEmitter.create(bridge, classSource);
ValueEmitter thisVar = pe.var(0, implementor);
ValueEmitter[] arguments = new ValueEmitter[bridgeTypes.length - 1];
for (int i = 0; i < arguments.length; ++i) {
@ -239,7 +242,7 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
for (int i = 0; i < bridgeTypes.length - 1; ++i) {
ValueType type = types[i];
ValueType bridgeType = types[i];
ValueType bridgeType = bridgeTypes[i];
if (type.equals(bridgeType)) {
continue;
}

View File

@ -90,7 +90,7 @@ public class AnnotationDependencyListener extends AbstractDependencyListener {
implementor.addField(field);
MethodHolder accessor = new MethodHolder(methodDecl.getDescriptor());
ProgramEmitter pe = ProgramEmitter.create(accessor);
ProgramEmitter pe = ProgramEmitter.create(accessor, classSource);
ValueEmitter thisVal = pe.var(0, implementor);
ValueEmitter result = thisVal.getField(field.getName(), field.getType());
if (field.getType() instanceof ValueType.Array) {
@ -104,7 +104,7 @@ public class AnnotationDependencyListener extends AbstractDependencyListener {
ctorSignature.add(ValueType.VOID);
MethodHolder ctor = new MethodHolder("<init>", ctorSignature.toArray(new ValueType[ctorSignature.size()]));
ProgramEmitter pe = ProgramEmitter.create(ctor);
ProgramEmitter pe = ProgramEmitter.create(ctor, classSource);
ValueEmitter thisVar = pe.var(0, implementor);
thisVar.invokeSpecial(Object.class, "<init>");
int index = 1;
@ -119,7 +119,7 @@ public class AnnotationDependencyListener extends AbstractDependencyListener {
implementor.addMethod(ctor);
MethodHolder annotTypeMethod = new MethodHolder("annotationType", ValueType.parse(Class.class));
pe = ProgramEmitter.create(annotTypeMethod);
pe = ProgramEmitter.create(annotTypeMethod, classSource);
pe.constant(ValueType.object(annotationType)).returnValue();
implementor.addMethod(annotTypeMethod);
@ -164,7 +164,7 @@ public class AnnotationDependencyListener extends AbstractDependencyListener {
MethodHolder ctor = new MethodHolder("<init>", ValueType.VOID);
ctor.setLevel(AccessLevel.PUBLIC);
ProgramEmitter pe = ProgramEmitter.create(ctor);
ProgramEmitter pe = ProgramEmitter.create(ctor, agent.getClassSource());
ValueEmitter thisVar = pe.var(0, cls);
thisVar.invokeSpecial(Object.class, "<init>").exit();
@ -178,7 +178,7 @@ public class AnnotationDependencyListener extends AbstractDependencyListener {
private MethodHolder addReader(DependencyAgent agent, ClassReader cls) {
MethodHolder readerMethod = new MethodHolder("getAnnotations", ValueType.parse(Annotation[].class));
readerMethod.setLevel(AccessLevel.PUBLIC);
ProgramEmitter pe = ProgramEmitter.create(readerMethod);
ProgramEmitter pe = ProgramEmitter.create(readerMethod, agent.getClassSource());
List<AnnotationReader> annotations = new ArrayList<>();
for (AnnotationReader annot : cls.getAnnotations().all()) {
@ -198,7 +198,7 @@ public class AnnotationDependencyListener extends AbstractDependencyListener {
ValueEmitter array = pe.constructArray(Annotation.class, annotations.size());
for (int i = 0; i < annotations.size(); ++i) {
array.unwrapArray().setElement(i, generateAnnotationInstance(agent, pe, annotations.get(i)));
array.setElement(i, generateAnnotationInstance(agent, pe, annotations.get(i)));
}
array.returnValue();
@ -250,7 +250,7 @@ public class AnnotationDependencyListener extends AbstractDependencyListener {
ValueType itemType = ((ValueType.Array) type).getItemType();
ValueEmitter array = pe.constructArray(itemType, list.size());
for (int i = 0; i < list.size(); ++i) {
array.unwrapArray().setElement(i, generateAnnotationValue(agent, pe, itemType, list.get(i)));
array.setElement(i, generateAnnotationValue(agent, pe, itemType, list.get(i)));
}
return array;
}

View File

@ -187,7 +187,7 @@ class DependencyGraphBuilder {
if (program == null) {
return;
}
ProgramEmitter pe = ProgramEmitter.create(program);
ProgramEmitter pe = ProgramEmitter.create(program, dependencyChecker.getClassSource());
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (int j = 0; j < block.getInstructions().size(); ++j) {
@ -229,7 +229,7 @@ class DependencyGraphBuilder {
}
}
pe.setBlock(block);
pe.enter(block);
pe.setCurrentLocation(indy.getLocation());
block.getInstructions().remove(j);

View File

@ -19,6 +19,7 @@ import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@ -113,24 +114,44 @@ public interface ClassReaderSource {
.filter(candidate -> candidate != null);
}
default boolean isSuperType(String superType, String subType) {
default Optional<Boolean> isSuperType(String superType, String subType) {
if (superType.equals(subType)) {
return true;
return Optional.of(true);
}
ClassReader cls = get(subType);
if (subType == null) {
return false;
return Optional.empty();
}
if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) {
if (isSuperType(superType, cls.getParent())) {
return true;
if (isSuperType(superType, cls.getParent()).orElse(false)) {
return Optional.of(true);
}
}
for (String iface : cls.getInterfaces()) {
if (isSuperType(superType, iface)) {
return true;
if (isSuperType(superType, iface).orElse(false)) {
return Optional.of(true);
}
}
return false;
return Optional.of(false);
}
default Optional<Boolean> isSuperType(ValueType superType, ValueType subType) {
if (superType.equals(subType)) {
return Optional.of(true);
}
if (superType instanceof ValueType.Primitive || subType instanceof ValueType.Primitive) {
return Optional.of(false);
}
if (superType.isObject("java.lang.Object")) {
return Optional.of(true);
}
if (superType instanceof ValueType.Object && subType instanceof ValueType.Object) {
return isSuperType(((ValueType.Object) superType).getClassName(),
((ValueType.Object) subType).getClassName());
} else if (superType instanceof ValueType.Array & subType instanceof ValueType.Array) {
return isSuperType(((ValueType.Array) superType).getItemType(), ((ValueType.Array) subType).getItemType());
} else {
return Optional.of(false);
}
}
}

View File

@ -38,14 +38,16 @@ public class ChooseEmitter {
public ChooseEmitter option(int value, FragmentEmitter fragment) {
SwitchTableEntry entry = new SwitchTableEntry();
entry.setCondition(value);
entry.setTarget(pe.createBlock());
entry.setTarget(pe.prepareBlock());
pe.enter(entry.getTarget());
fragment.emit();
pe.jump(joinBlock);
return this;
}
public ProgramEmitter otherwise(FragmentEmitter fragment) {
insn.setDefaultTarget(pe.createBlock());
insn.setDefaultTarget(pe.prepareBlock());
pe.enter(insn.getDefaultTarget());
fragment.emit();
pe.jump(joinBlock);
return pe;

View File

@ -16,8 +16,6 @@
package org.teavm.model.emit;
import org.teavm.model.BasicBlock;
import org.teavm.model.instructions.BinaryBranchingCondition;
import org.teavm.model.instructions.BranchingCondition;
/**
*
@ -25,38 +23,26 @@ import org.teavm.model.instructions.BranchingCondition;
*/
public class ConditionEmitter {
private ProgramEmitter pe;
private ComputationEmitter argument;
private BasicBlock join;
ForkEmitter fork;
ConditionEmitter(ProgramEmitter pe, ComputationEmitter argument, BasicBlock join) {
ConditionEmitter(ProgramEmitter pe, ForkEmitter fork) {
this.pe = pe;
this.argument = argument;
this.join = join;
this.fork = fork;
}
public IfEmitter isTrue() {
return new IfEmitter(pe, argument.emit().fork(BranchingCondition.NOT_EQUAL), join);
public ConditionEmitter and(ConditionProducer other) {
BasicBlock block = pe.prepareBlock();
pe.enter(block);
ConditionEmitter otherEmitter = other.produce();
ForkEmitter newFork = fork.and(block, otherEmitter.fork);
return new ConditionEmitter(pe, newFork);
}
public IfEmitter isFalse() {
return new IfEmitter(pe, argument.emit().fork(BranchingCondition.NOT_NULL), join);
}
public IfEmitter equalTo(ComputationEmitter other) {
return new IfEmitter(pe, argument.emit().fork(BinaryBranchingCondition.EQUAL, other.emit()), join);
}
public IfEmitter notEqualTo(ComputationEmitter other) {
return new IfEmitter(pe, argument.emit().fork(BinaryBranchingCondition.NOT_EQUAL, other.emit()), join);
}
public IfEmitter sameAs(ComputationEmitter other) {
return new IfEmitter(pe, argument.emit().fork(BinaryBranchingCondition.REFERENCE_EQUAL, other.emit()),
join);
}
public IfEmitter notSameAs(ComputationEmitter other) {
return new IfEmitter(pe, argument.emit().fork(BinaryBranchingCondition.REFERENCE_NOT_EQUAL, other.emit()),
join);
public ConditionEmitter or(ConditionProducer other) {
BasicBlock block = pe.prepareBlock();
pe.enter(block);
ConditionEmitter otherEmitter = other.produce();
ForkEmitter newFork = fork.or(block, otherEmitter.fork);
return new ConditionEmitter(pe, newFork);
}
}

View File

@ -0,0 +1,25 @@
/*
* 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
*/
@FunctionalInterface
public interface ConditionProducer {
ConditionEmitter produce();
}

View File

@ -0,0 +1,32 @@
/*
* 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 class EmitException extends RuntimeException {
private static final long serialVersionUID = 7479098357353665286L;
public EmitException() {
super();
}
public EmitException(String message) {
super(message);
}
}

View File

@ -30,25 +30,23 @@ public class IfEmitter {
this.pe = pe;
this.fork = fork;
this.join = join;
}
public ConditionEmitter and(ComputationEmitter condition) {
return new ConditionEmitter(pe, condition, join);
}
public ConditionEmitter or(ComputationEmitter condition) {
return new ConditionEmitter(pe, condition, join);
fork.setThen(join);
fork.setElse(join);
}
public IfEmitter thenDo(FragmentEmitter fragment) {
fork.setThen(pe.createBlock());
BasicBlock block = pe.prepareBlock();
fork.setThen(block);
pe.enter(block);
fragment.emit();
pe.jump(join);
return this;
}
public IfEmitter elseDo(FragmentEmitter fragment) {
fork.setThen(pe.createBlock());
BasicBlock block = pe.prepareBlock();
fork.setThen(block);
pe.enter(block);
fragment.emit();
pe.jump(join);
return this;

View File

@ -17,6 +17,8 @@ package org.teavm.model.emit;
import org.teavm.model.BasicBlock;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.FieldReader;
import org.teavm.model.FieldReference;
import org.teavm.model.Instruction;
import org.teavm.model.InstructionLocation;
@ -51,11 +53,13 @@ import org.teavm.model.instructions.SwitchInstruction;
public final class ProgramEmitter {
private Program program;
private BasicBlock block;
ClassReaderSource classSource;
private InstructionLocation currentLocation;
private ProgramEmitter(Program program, BasicBlock block) {
private ProgramEmitter(Program program, BasicBlock block, ClassReaderSource classSource) {
this.program = program;
this.block = block;
this.classSource = classSource;
}
public Program getProgram() {
@ -66,14 +70,13 @@ public final class ProgramEmitter {
return block;
}
public void setBlock(BasicBlock block) {
public ProgramEmitter enter(BasicBlock block) {
this.block = block;
return this;
}
public BasicBlock createBlock() {
BasicBlock block = program.createBasicBlock();
setBlock(block);
return block;
public BasicBlock prepareBlock() {
return program.createBasicBlock();
}
public ValueEmitter constant(Class<?> cls) {
@ -143,6 +146,11 @@ public final class ProgramEmitter {
}
public ValueEmitter getField(FieldReference field, ValueType type) {
FieldReader resolvedField = classSource.resolve(field);
if (resolvedField != null) {
field = resolvedField.getReference();
}
Variable var = program.createVariable();
GetFieldInstruction insn = new GetFieldInstruction();
insn.setField(field);
@ -161,6 +169,11 @@ public final class ProgramEmitter {
}
public ProgramEmitter setField(FieldReference field, ValueEmitter value) {
FieldReader resolvedField = classSource.resolve(field);
if (resolvedField != null) {
field = resolvedField.getReference();
}
PutFieldInstruction insn = new PutFieldInstruction();
insn.setField(field);
insn.setFieldType(value.type);
@ -173,6 +186,30 @@ public final class ProgramEmitter {
return setField(new FieldReference(className, fieldName), value);
}
public ValueEmitter invoke(MethodReference method, ValueEmitter... arguments) {
for (int i = 0; i < method.parameterCount(); ++i) {
if (!classSource.isSuperType(method.parameterType(i), arguments[i].getType()).orElse(true)) {
throw new EmitException("Argument " + i + " of type " + arguments[i].getType() + " is "
+ "not compatible with method " + method);
}
}
Variable result = null;
if (method.getReturnType() != ValueType.VOID) {
result = program.createVariable();
}
InvokeInstruction insn = new InvokeInstruction();
insn.setType(InvocationType.SPECIAL);
insn.setMethod(method);
insn.setReceiver(result);
for (ValueEmitter arg : arguments) {
insn.getArguments().add(arg.variable);
}
addInstruction(insn);
return result != null ? var(result, method.getReturnType()) : null;
}
public ValueEmitter invoke(String className, String methodName, ValueType resultType, ValueEmitter... arguments) {
Variable result = null;
if (resultType != ValueType.VOID) {
@ -314,7 +351,7 @@ public final class ProgramEmitter {
block.getInstructions().add(insn);
}
public static ProgramEmitter create(MethodHolder method) {
public static ProgramEmitter create(MethodHolder method, ClassReaderSource classSource) {
Program program = new Program();
method.setProgram(program);
BasicBlock zeroBlock = program.createBasicBlock();
@ -329,11 +366,15 @@ public final class ProgramEmitter {
program.createVariable();
}
return new ProgramEmitter(program, block);
return new ProgramEmitter(program, block, classSource);
}
public ConditionEmitter when(ComputationEmitter condition) {
return new ConditionEmitter(this, condition, program.createBasicBlock());
public IfEmitter when(ConditionEmitter cond) {
return new IfEmitter(this, cond.fork, prepareBlock());
}
public IfEmitter when(ConditionProducer cond) {
return when(cond.produce());
}
public PhiEmitter phi(ValueType type, BasicBlock block) {
@ -370,7 +411,11 @@ public final class ProgramEmitter {
return new ChooseEmitter(this, insn, program.createBasicBlock());
}
public static ProgramEmitter create(Program program) {
return new ProgramEmitter(program, null);
public ClassReaderSource getClassSource() {
return classSource;
}
public static ProgramEmitter create(Program program, ClassReaderSource classSource) {
return new ProgramEmitter(program, null, classSource);
}
}

View File

@ -16,8 +16,10 @@
package org.teavm.model.emit;
import org.teavm.model.BasicBlock;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.FieldReference;
import org.teavm.model.Incoming;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.model.Phi;
import org.teavm.model.PrimitiveType;
@ -84,7 +86,7 @@ public class ValueEmitter {
public ValueEmitter getField(String name, ValueType type) {
if (!(this.type instanceof ValueType.Object)) {
throw new IllegalStateException("Can't get field of non-object type: " + type);
throw new EmitException("Can't get field of non-object type: " + type);
}
String className = ((ValueType.Object) this.type).getClassName();
@ -102,9 +104,9 @@ public class ValueEmitter {
return getField(name, ValueType.parse(type));
}
public void setField(String name, ValueEmitter value) {
public ProgramEmitter setField(String name, ValueEmitter value) {
if (!(type instanceof ValueType.Object)) {
throw new IllegalStateException("Can't get field of non-object type: " + type);
throw new EmitException("Can't get field of non-object type: " + type);
}
String className = ((ValueType.Object) type).getClassName();
@ -114,6 +116,7 @@ public class ValueEmitter {
insn.setInstance(variable);
insn.setValue(value.getVariable());
pe.addInstruction(insn);
return pe;
}
static class Pair {
@ -128,20 +131,20 @@ public class ValueEmitter {
private Pair commonNumeric(ValueEmitter other) {
if (!(type instanceof ValueType.Primitive)) {
throw new IllegalArgumentException("First argument is not a primitive: " + type);
throw new EmitException("First argument is not a primitive: " + type);
}
if (!(other.type instanceof ValueType.Primitive)) {
throw new IllegalArgumentException("First argument is not a primitive: " + other.type);
throw new EmitException("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);
throw new EmitException("First argument is not numeric: " + type);
}
if (secondType == PrimitiveType.BOOLEAN) {
throw new IllegalArgumentException("Second argument is not numeric: " + other.type);
throw new EmitException("Second argument is not numeric: " + other.type);
}
ValueEmitter a = this;
@ -312,7 +315,7 @@ public class ValueEmitter {
switch (common) {
case FLOAT:
case DOUBLE:
throw new IllegalArgumentException("Can't perform bitwise operation between non-integers: " + common);
throw new EmitException("Can't perform bitwise operation between non-integers: " + common);
default:
break;
}
@ -364,7 +367,7 @@ public class ValueEmitter {
private ValueEmitter shift(BinaryOperation op, ValueEmitter other) {
if (!(type instanceof ValueType.Primitive) || !(other.type instanceof ValueType.Primitive)) {
throw new IllegalArgumentException("Can't shift " + type + " by " + other.type);
throw new EmitException("Can't shift " + type + " by " + other.type);
}
ValueType valueType = type;
@ -372,7 +375,7 @@ public class ValueEmitter {
switch (kind) {
case FLOAT:
case DOUBLE:
throw new IllegalArgumentException("Can't perform bit shift operation over non-integer: " + type);
throw new EmitException("Can't perform bit shift operation over non-integer: " + type);
default:
break;
}
@ -384,7 +387,7 @@ public class ValueEmitter {
case INTEGER:
break;
default:
throw new IllegalArgumentException("Can't perform bit shift operation with non-integer "
throw new EmitException("Can't perform bit shift operation with non-integer "
+ "shift: " + type);
}
other = other.castToInteger(convertToIntegerSubtype(shiftKind));
@ -399,10 +402,48 @@ public class ValueEmitter {
return binaryOp(op, value, other, valueType);
}
public ValueEmitter invoke(InvocationType invokeType, MethodReference method, ValueEmitter... arguments) {
if (!(type instanceof ValueType.Object)) {
throw new EmitException("Can't invoke method on non-object type: " + type);
}
ClassReaderSource classSource = pe.getClassSource();
for (int i = 0; i < method.parameterCount(); ++i) {
if (!classSource.isSuperType(method.parameterType(i), arguments[i].getType()).orElse(false)) {
throw new EmitException("Argument " + i + " of type " + arguments[i].getType() + " is "
+ "not compatible with method " + method);
}
}
if (!pe.classSource.isSuperType(((ValueType.Object) type).getClassName(), method.getClassName())
.orElse(true)) {
throw new EmitException("Can't call " + method + " on non-compatible class " + type);
}
MethodReader resolvedMethod = pe.classSource.resolve(method);
if (resolvedMethod != null) {
method = resolvedMethod.getReference();
}
Variable result = null;
if (method.getReturnType() != ValueType.VOID) {
result = pe.getProgram().createVariable();
}
InvokeInstruction insn = new InvokeInstruction();
insn.setType(invokeType);
insn.setMethod(method);
insn.setInstance(variable);
insn.setReceiver(result);
for (ValueEmitter arg : arguments) {
insn.getArguments().add(arg.variable);
}
pe.addInstruction(insn);
return result != null ? pe.var(result, method.getReturnType()) : null;
}
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);
throw new EmitException("Can't invoke method on non-object type: " + type);
}
Variable result = null;
@ -433,6 +474,10 @@ public class ValueEmitter {
return invoke(invokeType, ((ValueType.Object) type).getClassName(), name, resultType, arguments);
}
public ValueEmitter invokeSpecial(MethodReference method, ValueEmitter... arguments) {
return invoke(InvocationType.SPECIAL, method, arguments);
}
public ValueEmitter invokeSpecial(String className, String name, ValueType resultType, ValueEmitter... arguments) {
return invoke(InvocationType.SPECIAL, className, name, resultType, arguments);
}
@ -464,15 +509,19 @@ public class ValueEmitter {
return invoke(InvocationType.VIRTUAL, name, resultType, arguments);
}
public ValueEmitter invokeVirtual(MethodReference method, ValueEmitter... arguments) {
return invoke(InvocationType.VIRTUAL, method, 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) {
public ProgramEmitter invokeVirtual(String name, ValueEmitter... arguments) {
invokeVirtual(name, ValueType.VOID, arguments);
return pe;
}
public ValueEmitter join(BasicBlock block, ValueEmitter other, BasicBlock otherBlock, ValueType type) {
Variable var = pe.getProgram().createVariable();
Phi phi = new Phi();
@ -522,6 +571,38 @@ public class ValueEmitter {
};
}
public ConditionEmitter isTrue() {
return new ConditionEmitter(pe, fork(BranchingCondition.NOT_EQUAL));
}
public ConditionEmitter isFalse() {
return new ConditionEmitter(pe, fork(BranchingCondition.EQUAL));
}
public ConditionEmitter isEqualTo(ValueEmitter other) {
return new ConditionEmitter(pe, fork(BinaryBranchingCondition.NOT_EQUAL, other));
}
public ConditionEmitter isNotEqualTo(ValueEmitter other) {
return new ConditionEmitter(pe, fork(BinaryBranchingCondition.EQUAL, other));
}
public ConditionEmitter isGreaterThan(ValueEmitter other) {
return new ConditionEmitter(pe, compareTo(other).fork(BranchingCondition.GREATER));
}
public ConditionEmitter isGreaterOrEqualTo(ValueEmitter other) {
return new ConditionEmitter(pe, compareTo(other).fork(BranchingCondition.GREATER_OR_EQUAL));
}
public ConditionEmitter isLessThan(ValueEmitter other) {
return new ConditionEmitter(pe, compareTo(other).fork(BranchingCondition.LESS));
}
public ConditionEmitter isLessOrEuqalTo(ValueEmitter other) {
return new ConditionEmitter(pe, compareTo(other).fork(BranchingCondition.LESS_OR_EQUAL));
}
public void returnValue() {
ExitInstruction insn = new ExitInstruction();
insn.setValueToReturn(variable);
@ -529,6 +610,10 @@ public class ValueEmitter {
}
public void raise() {
if (!pe.classSource.isSuperType(ValueType.object("java.lang.Throwable"), type).orElse(true)) {
throw new EmitException("Can't throw non-exception value: " + type);
}
RaiseInstruction insn = new RaiseInstruction();
insn.setException(variable);
pe.addInstruction(insn);
@ -539,12 +624,13 @@ public class ValueEmitter {
}
public ValueEmitter cast(ValueType type) {
if (type.equals(this.type)) {
if (type.equals(this.type) || pe.classSource.isSuperType(type, this.type).orElse(false)) {
return this;
}
if (type instanceof ValueType.Primitive) {
if (!(this.type instanceof ValueType.Primitive)) {
throw new IllegalStateException("Can't convert " + this.type + " to " + type);
throw new EmitException("Can't convert " + this.type + " to " + type);
}
ValueEmitter value = this;
@ -552,7 +638,7 @@ public class ValueEmitter {
PrimitiveType targetKind = ((ValueType.Primitive) type).getKind();
if (sourceKind == PrimitiveType.BOOLEAN || targetKind == PrimitiveType.BOOLEAN) {
throw new IllegalStateException("Can't convert " + this.type + " to " + type);
throw new EmitException("Can't convert " + this.type + " to " + type);
}
IntegerSubtype sourceSubtype = convertToIntegerSubtype(sourceKind);
@ -577,7 +663,7 @@ public class ValueEmitter {
return value;
} else {
if (this.type instanceof ValueType.Primitive) {
throw new IllegalStateException("Can't convert " + this.type + " to " + type);
throw new EmitException("Can't convert " + this.type + " to " + type);
}
Variable result = pe.getProgram().createVariable();
CastInstruction insn = new CastInstruction();
@ -591,7 +677,7 @@ public class ValueEmitter {
public ValueEmitter cast(NumericOperandType to) {
if (!(type instanceof ValueType.Primitive)) {
throw new IllegalStateException("Can't cast non-primitive type: " + type);
throw new EmitException("Can't cast non-primitive type: " + type);
}
ValueEmitter value = this;
@ -611,7 +697,11 @@ public class ValueEmitter {
return result;
}
private ValueEmitter castFromInteger(IntegerSubtype subtype) {
public ValueEmitter castFromInteger(IntegerSubtype subtype) {
if (type != ValueType.INTEGER) {
throw new EmitException("Can't cast non-integer value: " + type);
}
CastIntegerInstruction insn = new CastIntegerInstruction(subtype, CastIntegerDirection.TO_INTEGER);
insn.setValue(variable);
ValueEmitter result = pe.newVar(ValueType.INTEGER);
@ -620,7 +710,25 @@ public class ValueEmitter {
return result;
}
private ValueEmitter castToInteger(IntegerSubtype subtype) {
public ValueEmitter castToInteger(IntegerSubtype subtype) {
switch (subtype) {
case BYTE:
if (type != ValueType.BYTE) {
throw new EmitException("Can't cast non-byte value: " + type);
}
break;
case SHORT:
if (type != ValueType.SHORT) {
throw new EmitException("Can't cast non-short value: " + type);
}
break;
case CHARACTER:
if (type != ValueType.CHARACTER) {
throw new EmitException("Can't cast non-char value: " + type);
}
break;
}
CastIntegerInstruction insn = new CastIntegerInstruction(subtype, CastIntegerDirection.FROM_INTEGER);
insn.setValue(variable);
ValueEmitter result = pe.newVar(ValueType.INTEGER);
@ -629,15 +737,44 @@ public class ValueEmitter {
return result;
}
public ValueEmitter getElement(ValueEmitter index) {
if (!(type instanceof ValueType.Array)) {
throw new IllegalArgumentException("Can't get element of non-array type: " + type);
public ValueEmitter widenToInteger() {
if (!(type instanceof ValueType.Primitive)) {
throw new EmitException("Can't widen non-primitive: " + type);
}
PrimitiveType primitive = ((ValueType.Primitive) type).getKind();
if (primitive == PrimitiveType.INTEGER) {
return this;
}
IntegerSubtype subtype = convertToIntegerSubtype(primitive);
if (subtype == null) {
throw new EmitException("Can't widen to int: " + type);
}
return castToInteger(subtype);
}
public ValueEmitter assertIs(ValueType type) {
if (!pe.classSource.isSuperType(type, this.type).orElse(true)) {
throw new EmitException("Value type " + this.type + " is not subtype of " + type);
}
return this;
}
public ValueEmitter assertIs(Class<?> type) {
return assertIs(ValueType.parse(type));
}
public ValueEmitter getElement(ValueEmitter index) {
if (!(type instanceof ValueType.Array)) {
throw new EmitException("Can't get element of non-array type: " + type);
}
ValueEmitter array = unwrapArray();
Variable result = pe.getProgram().createVariable();
GetElementInstruction insn = new GetElementInstruction();
insn.setArray(variable);
insn.setIndex(index.variable);
insn.setArray(array.variable);
insn.setIndex(index.widenToInteger().variable);
insn.setReceiver(result);
pe.addInstruction(insn);
return pe.var(result, ((ValueType.Array) type).getItemType());
@ -647,23 +784,25 @@ public class ValueEmitter {
return getElement(pe.constant(index));
}
public void setElement(ValueEmitter index, ValueEmitter value) {
PutElementInstruction insn = new PutElementInstruction();
insn.setArray(variable);
insn.setIndex(index.variable);
insn.setValue(value.variable);
pe.addInstruction(insn);
}
public void setElement(int index, ValueEmitter value) {
setElement(pe.constant(index), value);
}
public ValueEmitter unwrapArray() {
public ProgramEmitter setElement(ValueEmitter index, ValueEmitter value) {
if (!(type instanceof ValueType.Array)) {
throw new IllegalStateException("Can't unwrap non-array value: " + type);
throw new EmitException("Can't set element of non-array type: " + type);
}
PutElementInstruction insn = new PutElementInstruction();
insn.setArray(unwrapArray().variable);
insn.setIndex(index.widenToInteger().variable);
insn.setValue(value.variable);
pe.addInstruction(insn);
return pe;
}
public ProgramEmitter setElement(int index, ValueEmitter value) {
setElement(pe.constant(index), value);
return pe;
}
private ValueEmitter unwrapArray() {
ValueType elementType = ((ValueType.Array) type).getItemType();
Variable result = pe.getProgram().createVariable();
UnwrapArrayInstruction insn = new UnwrapArrayInstruction(getArrayElementType(elementType));
@ -674,9 +813,13 @@ public class ValueEmitter {
}
public ValueEmitter arrayLength() {
if (!(type instanceof ValueType.Array)) {
throw new EmitException("Can't get length of non-array type: " + type);
}
Variable result = pe.getProgram().createVariable();
ArrayLengthInstruction insn = new ArrayLengthInstruction();
insn.setArray(variable);
insn.setArray(unwrapArray().variable);
insn.setReceiver(result);
pe.addInstruction(insn);
return pe.var(result, ValueType.INTEGER);
@ -731,4 +874,36 @@ public class ValueEmitter {
phi.phi.getIncomings().add(incoming);
return pe;
}
public ValueEmitter box() {
if (!(type instanceof ValueType.Primitive)) {
throw new EmitException("Can't box non-primitive: " + type);
}
String className = getPrimitiveClassName(((ValueType.Primitive) type).getKind());
return pe.invoke(className, "valueOf", ValueType.object(className), this);
}
private String getPrimitiveClassName(PrimitiveType type) {
switch (type) {
case BOOLEAN:
return "java.lang.Boolean";
case BYTE:
return "java.lang.Byte";
case SHORT:
return "java.lang.Short";
case CHARACTER:
return "java.lang.Character";
case INTEGER:
return "java.lang.Integer";
case LONG:
return "java.lang.Long";
case FLOAT:
return "java.lang.Float";
case DOUBLE:
return "java.lang.Double";
default:
throw new AssertionError("Unexpected primitive type: " + type);
}
}
}

View File

@ -39,7 +39,7 @@ class MetadataProviderTransformer implements ClassHolderTransformer {
for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) {
AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName());
if (providerAnnot != null) {
transformMetadataMethod(cls, method, diagnostics);
transformMetadataMethod(cls, method, diagnostics, innerSource);
}
providerAnnot = method.getAnnotations().get(ClassScopedMetadataProvider.class.getName());
if (providerAnnot != null) {
@ -62,7 +62,8 @@ class MetadataProviderTransformer implements ClassHolderTransformer {
}
}
private void transformMetadataMethod(ClassHolder cls, MethodHolder method, Diagnostics diagnostics) {
private void transformMetadataMethod(ClassHolder cls, MethodHolder method, Diagnostics diagnostics,
ClassReaderSource classSource) {
if (!validate(method, diagnostics)) {
return;
}
@ -89,15 +90,17 @@ class MetadataProviderTransformer implements ClassHolderTransformer {
createMethod.getAnnotations().add(refAnnot);
method.getModifiers().remove(ElementModifier.NATIVE);
ProgramEmitter pe = ProgramEmitter.create(method);
ProgramEmitter pe = ProgramEmitter.create(method, classSource);
ForkEmitter fork = pe.getField(field.getReference(), field.getType()).fork(
BinaryBranchingCondition.REFERENCE_NOT_EQUAL, pe.constantNull(field.getType()));
BasicBlock resourceFound = pe.createBlock();
BasicBlock resourceFound = pe.prepareBlock();
fork.setThen(resourceFound);
pe.getField(field.getReference(), field.getType()).returnValue();
fork.setElse(pe.createBlock());
BasicBlock block = pe.prepareBlock();
fork.setElse(block);
pe.enter(block);
pe.setField(field.getReference(), pe.invoke(createMethod.getReference().getClassName(),
createMethod.getReference().getName(), createMethod.getResultType()));
pe.jump(resourceFound);