mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-27 01:30:35 +08:00
Improving emit API
This commit is contained in:
parent
00a751ef13
commit
3eea8da7fa
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user