Move for-loop generators out of ExpressionCodegen, convert them to Kotlin

This commit is contained in:
Dmitry Petrov
2017-04-24 14:55:56 +03:00
parent e03a842317
commit bc1e1515fd
16 changed files with 946 additions and 685 deletions
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegen;
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
import org.jetbrains.kotlin.codegen.coroutines.ResolvedCallWithRealDescriptor;
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
import org.jetbrains.kotlin.codegen.forLoop.*;
import org.jetbrains.kotlin.codegen.inline.*;
import org.jetbrains.kotlin.codegen.intrinsics.*;
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsKt;
@@ -53,9 +54,7 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
@@ -422,7 +421,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
@NotNull
private Type asmType(@NotNull KotlinType type) {
public Type asmType(@NotNull KotlinType type) {
return typeMapper.mapType(type);
}
@@ -605,68 +604,18 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
private void generateFor(@NotNull KtForExpression forExpression) {
ResolvedCall<? extends CallableDescriptor> loopRangeCall = RangeCodegenUtil.getLoopRangeResolvedCall(forExpression, bindingContext);
if (loopRangeCall != null) {
AbstractForLoopGenerator optimizedForLoopGenerator = createOptimizedForLoopGeneratorOrNull(forExpression, loopRangeCall);
if (optimizedForLoopGenerator != null) {
generateForLoop(optimizedForLoopGenerator);
return;
}
}
KtExpression loopRange = forExpression.getLoopRange();
assert loopRange != null;
KotlinType loopRangeType = bindingContext.getType(loopRange);
assert loopRangeType != null;
Type asmLoopRangeType = asmType(loopRangeType);
if (asmLoopRangeType.getSort() == Type.ARRAY) {
generateForLoop(new ForInArrayLoopGenerator(forExpression));
}
else if (RangeCodegenUtil.isRange(loopRangeType)) {
generateForLoop(new ForInRangeInstanceLoopGenerator(forExpression));
}
else if (RangeCodegenUtil.isProgression(loopRangeType)) {
generateForLoop(new ForInProgressionExpressionLoopGenerator(forExpression));
}
else {
generateForLoop(new IteratorForLoopGenerator(forExpression));
}
}
@Nullable
private AbstractForLoopGenerator createOptimizedForLoopGeneratorOrNull(
@NotNull KtForExpression forExpression,
@NotNull ResolvedCall<? extends CallableDescriptor> loopRangeCall
) {
CallableDescriptor loopRangeCallee = loopRangeCall.getResultingDescriptor();
if (RangeCodegenUtil.isPrimitiveNumberRangeTo(loopRangeCallee)) {
return new ForInRangeLiteralLoopGenerator(forExpression, loopRangeCall);
}
else if (RangeCodegenUtil.isPrimitiveNumberDownTo(loopRangeCallee)) {
return new ForInDownToProgressionLoopGenerator(forExpression, loopRangeCall);
}
else if (RangeCodegenUtil.isArrayOrPrimitiveArrayIndices(loopRangeCallee)) {
return new ForInArrayIndicesRangeLoopGenerator(forExpression, loopRangeCall);
}
else if (RangeCodegenUtil.isCollectionIndices(loopRangeCallee)) {
return new ForInCollectionIndicesRangeLoopGenerator(forExpression, loopRangeCall);
}
else if (RangeCodegenUtil.isCharSequenceIndices(loopRangeCallee)) {
return new ForInCharSequenceIndicesRangeLoopGenerator(forExpression, loopRangeCall);
}
return null;
generateForLoop(ForLoopGeneratorsKt.getForLoopGenerator(this, forExpression));
}
@NotNull
private static KotlinType getExpectedReceiverType(@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall) {
public static KotlinType getExpectedReceiverType(@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall) {
ReceiverParameterDescriptor extensionReceiver = resolvedCall.getResultingDescriptor().getExtensionReceiverParameter();
assert extensionReceiver != null : "Extension receiver should be non-null";
return extensionReceiver.getType();
}
@Nullable
private static KtExpression getSingleArgumentExpression(@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall) {
public static KtExpression getSingleArgumentExpression(@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall) {
List<ResolvedValueArgument> resolvedValueArguments = resolvedCall.getValueArgumentsByIndex();
if (resolvedValueArguments == null) return null;
if (resolvedValueArguments.size() != 1) return null;
@@ -694,7 +643,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
PseudoInsnsKt.fakeAlwaysFalseIfeq(v, continueLabel);
generator.beforeBody();
blockStackElements.push(new LoopBlockStackElement(loopExit, continueLabel, targetLabel(generator.forExpression)));
blockStackElements.push(new LoopBlockStackElement(loopExit, continueLabel, targetLabel(generator.getForExpression())));
generator.body();
blockStackElements.pop();
v.mark(continueLabel);
@@ -706,616 +655,12 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
generator.afterLoop();
}
private abstract class AbstractForLoopGenerator {
// for (e : E in c) {...}
protected final KtForExpression forExpression;
private final Label loopParameterStartLabel = new Label();
private final Label bodyEnd = new Label();
private final List<Runnable> leaveVariableTasks = Lists.newArrayList();
protected final KotlinType elementType;
protected final Type asmElementType;
protected int loopParameterVar;
protected Type loopParameterType;
private AbstractForLoopGenerator(@NotNull KtForExpression forExpression) {
this.forExpression = forExpression;
this.elementType = getElementType(forExpression);
this.asmElementType = asmType(elementType);
}
@NotNull
private KotlinType getElementType(KtForExpression forExpression) {
KtExpression loopRange = forExpression.getLoopRange();
assert loopRange != null;
ResolvedCall<FunctionDescriptor> nextCall = getNotNull(bindingContext,
LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange,
"No next() function " + DiagnosticUtils.atLocation(loopRange));
//noinspection ConstantConditions
return nextCall.getResultingDescriptor().getReturnType();
}
public void beforeLoop() {
KtParameter loopParameter = forExpression.getLoopParameter();
if (loopParameter == null) return;
KtDestructuringDeclaration multiParameter = loopParameter.getDestructuringDeclaration();
if (multiParameter != null) {
// E tmp<e> = tmp<iterator>.next()
loopParameterType = asmElementType;
loopParameterVar = createLoopTempVariable(asmElementType);
}
else {
// E e = tmp<iterator>.next()
VariableDescriptor parameterDescriptor = bindingContext.get(VALUE_PARAMETER, loopParameter);
loopParameterType = asmType(parameterDescriptor.getType());
loopParameterVar = myFrameMap.enter(parameterDescriptor, loopParameterType);
scheduleLeaveVariable(() -> {
myFrameMap.leave(parameterDescriptor);
v.visitLocalVariable(parameterDescriptor.getName().asString(),
loopParameterType.getDescriptor(), null,
loopParameterStartLabel, bodyEnd,
loopParameterVar);
});
}
}
public abstract void checkEmptyLoop(@NotNull Label loopExit);
public abstract void checkPreCondition(@NotNull Label loopExit);
public void beforeBody() {
assignToLoopParameter();
v.mark(loopParameterStartLabel);
KtDestructuringDeclaration destructuringDeclaration = forExpression.getDestructuringDeclaration();
if (destructuringDeclaration != null) {
generateDestructuringDeclaration(destructuringDeclaration);
}
}
private void generateDestructuringDeclaration(@NotNull KtDestructuringDeclaration destructuringDeclaration) {
Label destructuringStartLabel = new Label();
List<VariableDescriptor> componentDescriptors =
CollectionsKt.map(destructuringDeclaration.getEntries(), ExpressionCodegen.this::getVariableDescriptorNotNull);
for (VariableDescriptor componentDescriptor : CodegenUtilKt.filterOutDescriptorsWithSpecialNames(componentDescriptors)) {
@SuppressWarnings("ConstantConditions") Type componentAsmType = asmType(componentDescriptor.getReturnType());
int componentVarIndex = myFrameMap.enter(componentDescriptor, componentAsmType);
scheduleLeaveVariable(() -> {
myFrameMap.leave(componentDescriptor);
v.visitLocalVariable(componentDescriptor.getName().asString(),
componentAsmType.getDescriptor(), null,
destructuringStartLabel, bodyEnd,
componentVarIndex);
});
}
v.visitLabel(destructuringStartLabel);
initializeDestructuringDeclarationVariables(
destructuringDeclaration,
new TransientReceiver(elementType),
StackValue.local(loopParameterVar, asmElementType));
}
protected abstract void assignToLoopParameter();
protected abstract void increment(@NotNull Label loopExit);
public void body() {
generateLoopBody(forExpression.getBody());
}
private void scheduleLeaveVariable(Runnable runnable) {
leaveVariableTasks.add(runnable);
}
protected int createLoopTempVariable(Type type) {
int varIndex = myFrameMap.enterTemp(type);
scheduleLeaveVariable(() -> myFrameMap.leaveTemp(type));
return varIndex;
}
public void afterBody(@NotNull Label loopExit) {
markStartLineNumber(forExpression);
increment(loopExit);
v.mark(bodyEnd);
}
public void afterLoop() {
for (Runnable task : Lists.reverse(leaveVariableTasks)) {
task.run();
}
}
// This method consumes range/progression from stack
// The result is stored to local variable
protected void generateRangeOrProgressionProperty(
@NotNull Type loopRangeType,
@NotNull String getterName,
@NotNull Type getterReturnType,
@NotNull Type varType,
int varToStore
) {
v.invokevirtual(loopRangeType.getInternalName(), getterName, "()" + getterReturnType.getDescriptor(), false);
StackValue.local(varToStore, varType).store(StackValue.onStack(getterReturnType), v);
}
}
private void generateLoopBody(@Nullable KtExpression body) {
public void generateLoopBody(@Nullable KtExpression body) {
if (body != null) {
gen(body, Type.VOID_TYPE);
}
}
private class IteratorForLoopGenerator extends AbstractForLoopGenerator {
private int iteratorVarIndex;
private final ResolvedCall<FunctionDescriptor> iteratorCall;
private final ResolvedCall<FunctionDescriptor> nextCall;
private final Type asmTypeForIterator;
private IteratorForLoopGenerator(@NotNull KtForExpression forExpression) {
super(forExpression);
KtExpression loopRange = forExpression.getLoopRange();
assert loopRange != null;
this.iteratorCall = getNotNull(bindingContext,
LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange,
"No .iterator() function " + DiagnosticUtils.atLocation(loopRange));
KotlinType iteratorType = iteratorCall.getResultingDescriptor().getReturnType();
assert iteratorType != null;
this.asmTypeForIterator = asmType(iteratorType);
this.nextCall = getNotNull(bindingContext,
LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange,
"No next() function " + DiagnosticUtils.atLocation(loopRange));
}
@Override
public void beforeLoop() {
super.beforeLoop();
// Iterator<E> tmp<iterator> = c.iterator()
iteratorVarIndex = createLoopTempVariable(asmTypeForIterator);
StackValue.local(iteratorVarIndex, asmTypeForIterator).store(invokeFunction(iteratorCall, StackValue.none()), v);
}
@Override
public void checkEmptyLoop(@NotNull Label loopExit) {
}
@Override
public void checkPreCondition(@NotNull Label loopExit) {
// tmp<iterator>.hasNext()
KtExpression loopRange = forExpression.getLoopRange();
@SuppressWarnings("ConstantConditions") ResolvedCall<FunctionDescriptor> hasNextCall = getNotNull(bindingContext,
LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, loopRange,
"No hasNext() function " + DiagnosticUtils.atLocation(loopRange));
@SuppressWarnings("ConstantConditions") Call fakeCall = makeFakeCall(new TransientReceiver(iteratorCall.getResultingDescriptor().getReturnType()));
StackValue result = invokeFunction(fakeCall, hasNextCall, StackValue.local(iteratorVarIndex, asmTypeForIterator));
result.put(Type.BOOLEAN_TYPE, v);
v.ifeq(loopExit);
}
@Override
protected void assignToLoopParameter() {
@SuppressWarnings("ConstantConditions") Call fakeCall =
makeFakeCall(new TransientReceiver(iteratorCall.getResultingDescriptor().getReturnType()));
StackValue value = invokeFunction(fakeCall, nextCall, StackValue.local(iteratorVarIndex, asmTypeForIterator));
//noinspection ConstantConditions
StackValue.local(loopParameterVar, loopParameterType).store(value, v);
}
@Override
protected void increment(@NotNull Label loopExit) {
}
}
private class ForInArrayLoopGenerator extends AbstractForLoopGenerator {
private int indexVar;
private int arrayVar;
private final KotlinType loopRangeType;
private ForInArrayLoopGenerator(@NotNull KtForExpression forExpression) {
super(forExpression);
loopRangeType = bindingContext.getType(forExpression.getLoopRange());
}
@Override
public void beforeLoop() {
super.beforeLoop();
indexVar = createLoopTempVariable(Type.INT_TYPE);
KtExpression loopRange = forExpression.getLoopRange();
StackValue value = gen(loopRange);
Type asmLoopRangeType = asmType(loopRangeType);
if (value instanceof StackValue.Local && value.type.equals(asmLoopRangeType)) {
arrayVar = ((StackValue.Local) value).index; // no need to copy local variable into another variable
}
else {
arrayVar = createLoopTempVariable(OBJECT_TYPE);
value.put(asmLoopRangeType, v);
v.store(arrayVar, OBJECT_TYPE);
}
v.iconst(0);
v.store(indexVar, Type.INT_TYPE);
}
@Override
public void checkEmptyLoop(@NotNull Label loopExit) {
}
@Override
public void checkPreCondition(@NotNull Label loopExit) {
v.load(indexVar, Type.INT_TYPE);
v.load(arrayVar, OBJECT_TYPE);
v.arraylength();
v.ificmpge(loopExit);
}
@Override
protected void assignToLoopParameter() {
Type arrayElParamType;
if (KotlinBuiltIns.isArray(loopRangeType)) {
arrayElParamType = boxType(asmElementType);
}
else {
arrayElParamType = asmElementType;
}
v.load(arrayVar, OBJECT_TYPE);
v.load(indexVar, Type.INT_TYPE);
v.aload(arrayElParamType);
StackValue.onStack(arrayElParamType).put(asmElementType, v);
v.store(loopParameterVar, asmElementType);
}
@Override
protected void increment(@NotNull Label loopExit) {
v.iinc(indexVar, 1);
}
}
private abstract class AbstractForInProgressionOrRangeLoopGenerator extends AbstractForLoopGenerator {
protected int endVar;
private StackValue loopParameter;
private AbstractForInProgressionOrRangeLoopGenerator(@NotNull KtForExpression forExpression) {
super(forExpression);
switch (asmElementType.getSort()) {
case Type.INT:
case Type.BYTE:
case Type.SHORT:
case Type.CHAR:
case Type.LONG:
break;
default:
throw new IllegalStateException("Unexpected range element type: " + asmElementType);
}
}
@Override
public void beforeLoop() {
super.beforeLoop();
endVar = createLoopTempVariable(asmElementType);
}
protected void checkPostCondition(@NotNull Label loopExit) {
assert endVar != -1 :
"endVar must be allocated, endVar = " + endVar;
loopParameter().put(asmElementType, v);
v.load(endVar, asmElementType);
if (asmElementType.getSort() == Type.LONG) {
v.lcmp();
v.ifeq(loopExit);
}
else {
v.ificmpeq(loopExit);
}
}
@Override
public void checkPreCondition(@NotNull Label loopExit) {
}
@NotNull
protected StackValue loopParameter() {
if (loopParameter == null) {
loopParameter = StackValue.local(loopParameterVar, loopParameterType);
}
return loopParameter;
}
}
private abstract class AbstractForInRangeLoopGenerator extends AbstractForInProgressionOrRangeLoopGenerator {
private final int step;
private AbstractForInRangeLoopGenerator(@NotNull KtForExpression forExpression, int step) {
super(forExpression);
this.step = step;
assert step == 1 || step == -1 : "'step' should be either 1 or -1: " + step;
}
private AbstractForInRangeLoopGenerator(@NotNull KtForExpression forExpression) {
this(forExpression, 1);
}
@Override
public void beforeLoop() {
super.beforeLoop();
storeRangeStartAndEnd();
}
protected abstract void storeRangeStartAndEnd();
@Override
public void checkEmptyLoop(@NotNull Label loopExit) {
loopParameter().put(asmElementType, v);
v.load(endVar, asmElementType);
if (asmElementType.getSort() == Type.LONG) {
v.lcmp();
if (step > 0) {
v.ifgt(loopExit);
}
else {
v.iflt(loopExit);
}
}
else {
if (step > 0) {
v.ificmpgt(loopExit);
}
else {
v.ificmplt(loopExit);
}
}
}
@Override
protected void assignToLoopParameter() {
}
@Override
protected void increment(@NotNull Label loopExit) {
checkPostCondition(loopExit);
if (loopParameterType == Type.INT_TYPE) {
v.iinc(loopParameterVar, step);
}
else {
StackValue loopParameter = loopParameter();
loopParameter.put(asmElementType, v);
genIncrement(asmElementType, step, v);
loopParameter.store(StackValue.onStack(asmElementType), v);
}
}
}
private class ForInRangeLiteralLoopGenerator extends AbstractForInRangeLoopGenerator {
private final ReceiverValue from;
private final KtExpression to;
private ForInRangeLiteralLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
super(forExpression);
this.from = loopRangeCall.getDispatchReceiver();
this.to = getSingleArgumentExpression(loopRangeCall);
}
@Override
protected void storeRangeStartAndEnd() {
loopParameter().store(generateReceiverValue(from, false), v);
StackValue.local(endVar, asmElementType).store(gen(to), v);
}
}
private class ForInDownToProgressionLoopGenerator extends AbstractForInRangeLoopGenerator {
private final ReceiverValue from;
private final KtExpression to;
private ForInDownToProgressionLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
super(forExpression, -1);
this.from = loopRangeCall.getExtensionReceiver();
this.to = getSingleArgumentExpression(loopRangeCall);
}
@Override
protected void storeRangeStartAndEnd() {
loopParameter().store(generateReceiverValue(from, false), v);
StackValue.local(endVar, asmElementType).store(gen(to), v);
}
}
private class ForInRangeInstanceLoopGenerator extends AbstractForInRangeLoopGenerator {
private ForInRangeInstanceLoopGenerator(@NotNull KtForExpression forExpression) {
super(forExpression);
}
@Override
protected void storeRangeStartAndEnd() {
KotlinType loopRangeType = bindingContext.getType(forExpression.getLoopRange());
assert loopRangeType != null;
Type asmLoopRangeType = asmType(loopRangeType);
gen(forExpression.getLoopRange(), asmLoopRangeType);
v.dup();
// ranges inherit first and last from corresponding progressions
generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterType, loopParameterVar);
generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, asmElementType, endVar);
}
}
private abstract class ForInOptimizedIndicesLoopGenerator extends AbstractForInRangeLoopGenerator {
protected final ReceiverValue receiverValue;
protected final KotlinType expectedReceiverType;
private ForInOptimizedIndicesLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
super(forExpression);
this.receiverValue = loopRangeCall.getExtensionReceiver();
this.expectedReceiverType = getExpectedReceiverType(loopRangeCall);
}
@Override
protected void storeRangeStartAndEnd() {
loopParameter().store(StackValue.constant(0, asmElementType), v);
StackValue receiver = generateReceiverValue(receiverValue, false);
Type receiverType = asmType(expectedReceiverType);
receiver.put(receiverType, v);
getReceiverSizeAsInt();
v.iconst(1);
v.sub(Type.INT_TYPE);
StackValue.local(endVar, asmElementType).store(StackValue.onStack(Type.INT_TYPE), v);
}
/**
* <code>(receiver -> size:I)</code>
*/
protected abstract void getReceiverSizeAsInt();
}
private class ForInCollectionIndicesRangeLoopGenerator extends ForInOptimizedIndicesLoopGenerator {
private ForInCollectionIndicesRangeLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
super(forExpression, loopRangeCall);
}
@Override
protected void getReceiverSizeAsInt() {
v.invokeinterface("java/util/Collection", "size", "()I");
}
}
private class ForInArrayIndicesRangeLoopGenerator extends ForInOptimizedIndicesLoopGenerator {
private ForInArrayIndicesRangeLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
super(forExpression, loopRangeCall);
}
@Override
protected void getReceiverSizeAsInt() {
v.arraylength();
}
}
private class ForInCharSequenceIndicesRangeLoopGenerator extends ForInOptimizedIndicesLoopGenerator {
private ForInCharSequenceIndicesRangeLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
super(forExpression, loopRangeCall);
}
@Override
protected void getReceiverSizeAsInt() {
v.invokeinterface("java/lang/CharSequence", "length", "()I");
}
}
private class ForInProgressionExpressionLoopGenerator extends AbstractForInProgressionOrRangeLoopGenerator {
private int incrementVar;
private Type incrementType;
private ForInProgressionExpressionLoopGenerator(@NotNull KtForExpression forExpression) {
super(forExpression);
}
@Override
public void beforeLoop() {
super.beforeLoop();
incrementVar = createLoopTempVariable(asmElementType);
KotlinType loopRangeType = bindingContext.getType(forExpression.getLoopRange());
assert loopRangeType != null;
Type asmLoopRangeType = asmType(loopRangeType);
Collection<PropertyDescriptor> incrementProp =
loopRangeType.getMemberScope().getContributedVariables(Name.identifier("step"), NoLookupLocation.FROM_BACKEND);
assert incrementProp.size() == 1 : loopRangeType + " " + incrementProp.size();
incrementType = asmType(incrementProp.iterator().next().getType());
gen(forExpression.getLoopRange(), asmLoopRangeType);
v.dup();
v.dup();
generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterType, loopParameterVar);
generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, asmElementType, endVar);
generateRangeOrProgressionProperty(asmLoopRangeType, "getStep", incrementType, incrementType, incrementVar);
}
@Override
public void checkEmptyLoop(@NotNull Label loopExit) {
loopParameter().put(asmElementType, v);
v.load(endVar, asmElementType);
v.load(incrementVar, incrementType);
Label negativeIncrement = new Label();
Label afterIf = new Label();
if (asmElementType.getSort() == Type.LONG) {
v.lconst(0L);
v.lcmp();
v.ifle(negativeIncrement); // if increment < 0, jump
// increment > 0
v.lcmp();
v.ifgt(loopExit);
v.goTo(afterIf);
// increment < 0
v.mark(negativeIncrement);
v.lcmp();
v.iflt(loopExit);
v.mark(afterIf);
}
else {
v.ifle(negativeIncrement); // if increment < 0, jump
// increment > 0
v.ificmpgt(loopExit);
v.goTo(afterIf);
// increment < 0
v.mark(negativeIncrement);
v.ificmplt(loopExit);
v.mark(afterIf);
}
}
@Override
protected void assignToLoopParameter() {
}
@Override
protected void increment(@NotNull Label loopExit) {
checkPostCondition(loopExit);
StackValue loopParameter = loopParameter();
loopParameter.put(asmElementType, v);
v.load(incrementVar, asmElementType);
v.add(asmElementType);
if (asmElementType == Type.BYTE_TYPE || asmElementType == Type.SHORT_TYPE || asmElementType == Type.CHAR_TYPE) {
StackValue.coerce(Type.INT_TYPE, asmElementType, v);
}
loopParameter.store(StackValue.onStack(asmElementType), v);
}
}
@Override
public StackValue visitBreakExpression(@NotNull KtBreakExpression expression, StackValue receiver) {
@@ -4187,7 +3532,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
@NotNull
private VariableDescriptor getVariableDescriptorNotNull(@NotNull KtElement declaration) {
public VariableDescriptor getVariableDescriptorNotNull(@NotNull KtElement declaration) {
VariableDescriptor descriptor = bindingContext.get(VARIABLE, declaration);
assert descriptor != null : "Couldn't find variable declaration in binding context " + declaration.getText();
return descriptor;
@@ -4774,7 +4119,7 @@ The "returned" value of try expression with no finally is either the last expres
}
}
private Call makeFakeCall(ReceiverValue initializerAsReceiver) {
public Call makeFakeCall(ReceiverValue initializerAsReceiver) {
KtSimpleNameExpression fake = KtPsiFactoryKt.KtPsiFactory(state.getProject(), false).createSimpleName("fake");
return CallMaker.makeCall(fake, initializerAsReceiver);
}
@@ -74,27 +74,6 @@ public class RangeCodegenUtil {
return !rangeType.isMarkedNullable() && getPrimitiveProgressionElementType(rangeType) != null;
}
@Nullable
public static ResolvedCall<? extends CallableDescriptor> getLoopRangeResolvedCall(@NotNull KtForExpression forExpression, @NotNull BindingContext bindingContext) {
KtExpression loopRange = KtPsiUtil.deparenthesize(forExpression.getLoopRange());
if (loopRange instanceof KtQualifiedExpression) {
KtQualifiedExpression qualifiedExpression = (KtQualifiedExpression) loopRange;
KtExpression selector = qualifiedExpression.getSelectorExpression();
if (selector instanceof KtCallExpression || selector instanceof KtSimpleNameExpression) {
return CallUtilKt.getResolvedCall(selector, bindingContext);
}
}
else if (loopRange instanceof KtSimpleNameExpression || loopRange instanceof KtCallExpression) {
return CallUtilKt.getResolvedCall(loopRange, bindingContext);
}
else if (loopRange instanceof KtBinaryExpression) {
return CallUtilKt.getResolvedCall(((KtBinaryExpression) loopRange).getOperationReference(), bindingContext);
}
return null;
}
@Nullable
private static PrimitiveType getPrimitiveRangeElementType(KotlinType rangeType) {
return getPrimitiveRangeOrProgressionElementType(rangeType, RANGE_TO_ELEMENT_TYPE);
@@ -0,0 +1,69 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.codegen.forLoop
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
abstract class AbstractForInProgressionOrRangeLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression)
: AbstractForLoopGenerator(codegen, forExpression)
{
protected var endVar: Int = 0
private var loopParameter: StackValue? = null
init {
assert(
asmElementType.sort == Type.INT ||
asmElementType.sort == Type.BYTE ||
asmElementType.sort == Type.SHORT ||
asmElementType.sort == Type.CHAR ||
asmElementType.sort == Type.LONG
) {
"Unexpected range element type: " + asmElementType
}
}
override fun beforeLoop() {
super.beforeLoop()
endVar = createLoopTempVariable(asmElementType)
}
protected fun checkPostCondition(loopExit: Label) {
assert(endVar != -1) {
"endVar must be allocated, endVar = " + endVar
}
loopParameter().put(asmElementType, v)
v.load(endVar, asmElementType)
if (asmElementType.sort == Type.LONG) {
v.lcmp()
v.ifeq(loopExit)
}
else {
v.ificmpeq(loopExit)
}
}
override fun checkPreCondition(loopExit: Label) {}
protected fun loopParameter(): StackValue =
loopParameter ?: StackValue.local(loopParameterVar, loopParameterType).also { loopParameter = it }
}
@@ -0,0 +1,82 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.codegen.forLoop
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.kotlin.codegen.AsmUtil.genIncrement
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
abstract class AbstractForInRangeLoopGenerator : AbstractForInProgressionOrRangeLoopGenerator {
private val step: Int
constructor(codegen: ExpressionCodegen, forExpression: KtForExpression, step: Int) : super(codegen, forExpression) {
assert(step == 1 || step == -1) { "'step' should be either 1 or -1: " + step }
this.step = step
}
constructor(codegen: ExpressionCodegen, forExpression: KtForExpression) : this(codegen, forExpression, 1)
override fun beforeLoop() {
super.beforeLoop()
storeRangeStartAndEnd()
}
protected abstract fun storeRangeStartAndEnd()
override fun checkEmptyLoop(loopExit: Label) {
loopParameter().put(asmElementType, v)
v.load(endVar, asmElementType)
if (asmElementType.sort == Type.LONG) {
v.lcmp()
if (step > 0) {
v.ifgt(loopExit)
}
else {
v.iflt(loopExit)
}
}
else {
if (step > 0) {
v.ificmpgt(loopExit)
}
else {
v.ificmplt(loopExit)
}
}
}
override fun assignToLoopParameter() {}
override fun increment(loopExit: Label) {
checkPostCondition(loopExit)
if (loopParameterType === Type.INT_TYPE) {
v.iinc(loopParameterVar, step)
}
else {
val loopParameter = loopParameter()
loopParameter.put(asmElementType, v)
genIncrement(asmElementType, step, v)
loopParameter.store(StackValue.onStack(asmElementType), v)
}
}
}
@@ -0,0 +1,161 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.codegen.forLoop
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.filterOutDescriptorsWithSpecialNames
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
abstract class AbstractForLoopGenerator(
protected val codegen: ExpressionCodegen,
val forExpression: KtForExpression
) {
protected val bindingContext = codegen.bindingContext
protected val v = codegen.v!!
private val loopParameterStartLabel = Label()
private val bodyEnd = Label()
private val leaveVariableTasks = arrayListOf<Runnable>()
protected val elementType: KotlinType = bindingContext.getElementType(forExpression)
protected val asmElementType: Type = codegen.asmType(elementType)
protected var loopParameterVar: Int = 0
protected lateinit var loopParameterType: Type
private fun BindingContext.getElementType(forExpression: KtForExpression): KotlinType {
val loopRange = forExpression.loopRange!!
val nextCall = get(BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange) ?:
throw AssertionError("No next() function " + DiagnosticUtils.atLocation(loopRange))
return nextCall.resultingDescriptor.returnType!!
}
open fun beforeLoop() {
val loopParameter = forExpression.loopParameter ?: return
val multiParameter = loopParameter.destructuringDeclaration
if (multiParameter != null) {
// E tmp<e> = tmp<iterator>.next()
loopParameterType = asmElementType
loopParameterVar = createLoopTempVariable(asmElementType)
}
else {
// E e = tmp<iterator>.next()
val parameterDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER, loopParameter)
loopParameterType = codegen.asmType(parameterDescriptor!!.type)
loopParameterVar = codegen.myFrameMap.enter(parameterDescriptor, loopParameterType)
scheduleLeaveVariable(Runnable {
codegen.myFrameMap.leave(parameterDescriptor)
v.visitLocalVariable(parameterDescriptor.name.asString(),
loopParameterType.descriptor, null,
loopParameterStartLabel, bodyEnd,
loopParameterVar)
})
}
}
abstract fun checkEmptyLoop(loopExit: Label)
abstract fun checkPreCondition(loopExit: Label)
fun beforeBody() {
assignToLoopParameter()
v.mark(loopParameterStartLabel)
val destructuringDeclaration = forExpression.destructuringDeclaration
if (destructuringDeclaration != null) {
generateDestructuringDeclaration(destructuringDeclaration)
}
}
private fun generateDestructuringDeclaration(destructuringDeclaration: KtDestructuringDeclaration) {
val destructuringStartLabel = Label()
val componentDescriptors = destructuringDeclaration.entries.map { declaration -> codegen.getVariableDescriptorNotNull(declaration) }
for (componentDescriptor in componentDescriptors.filterOutDescriptorsWithSpecialNames()) {
val componentAsmType = codegen.asmType(componentDescriptor.returnType!!)
val componentVarIndex = codegen.myFrameMap.enter(componentDescriptor, componentAsmType)
scheduleLeaveVariable(Runnable {
codegen.myFrameMap.leave(componentDescriptor)
v.visitLocalVariable(componentDescriptor.name.asString(),
componentAsmType.descriptor, null,
destructuringStartLabel, bodyEnd,
componentVarIndex)
})
}
v.visitLabel(destructuringStartLabel)
codegen.initializeDestructuringDeclarationVariables(
destructuringDeclaration,
TransientReceiver(elementType),
StackValue.local(loopParameterVar, asmElementType))
}
protected abstract fun assignToLoopParameter()
protected abstract fun increment(loopExit: Label)
fun body() {
codegen.generateLoopBody(forExpression.body)
}
private fun scheduleLeaveVariable(runnable: Runnable) {
leaveVariableTasks.add(runnable)
}
protected fun createLoopTempVariable(type: Type): Int {
val varIndex = codegen.myFrameMap.enterTemp(type)
scheduleLeaveVariable(Runnable { codegen.myFrameMap.leaveTemp(type) })
return varIndex
}
fun afterBody(loopExit: Label) {
codegen.markStartLineNumber(forExpression)
increment(loopExit)
v.mark(bodyEnd)
}
fun afterLoop() {
for (task in leaveVariableTasks.asReversed()) {
task.run()
}
}
// This method consumes range/progression from stack
// The result is stored to local variable
protected fun generateRangeOrProgressionProperty(
loopRangeType: Type,
getterName: String,
getterReturnType: Type,
varType: Type,
varToStore: Int
) {
v.invokevirtual(loopRangeType.internalName, getterName, "()" + getterReturnType.descriptor, false)
StackValue.local(varToStore, varType).store(StackValue.onStack(getterReturnType), v)
}
}
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.codegen.forLoop
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
class ForInArrayIndicesRangeLoopGenerator(
codegen: ExpressionCodegen,
forExpression: KtForExpression,
loopRangeCall: ResolvedCall<*>
) : ForInOptimizedIndicesLoopGenerator(codegen, forExpression, loopRangeCall) {
override fun getReceiverSizeAsInt() {
v.arraylength()
}
}
@@ -0,0 +1,80 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.codegen.forLoop
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.kotlin.codegen.AsmUtil.boxType
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
class ForInArrayLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression)
: AbstractForLoopGenerator(codegen, forExpression)
{
private var indexVar: Int = 0
private var arrayVar: Int = 0
private val loopRangeType: KotlinType = bindingContext.getType(forExpression.loopRange!!)!!
override fun beforeLoop() {
super.beforeLoop()
indexVar = createLoopTempVariable(Type.INT_TYPE)
val loopRange = forExpression.loopRange
val value = codegen.gen(loopRange)
val asmLoopRangeType = codegen.asmType(loopRangeType)
if (value is StackValue.Local && value.type == asmLoopRangeType) {
arrayVar = value.index // no need to copy local variable into another variable
}
else {
arrayVar = createLoopTempVariable(OBJECT_TYPE)
value.put(asmLoopRangeType, v)
v.store(arrayVar, OBJECT_TYPE)
}
v.iconst(0)
v.store(indexVar, Type.INT_TYPE)
}
override fun checkEmptyLoop(loopExit: Label) {}
override fun checkPreCondition(loopExit: Label) {
v.load(indexVar, Type.INT_TYPE)
v.load(arrayVar, OBJECT_TYPE)
v.arraylength()
v.ificmpge(loopExit)
}
override fun assignToLoopParameter() {
val arrayElParamType = if (KotlinBuiltIns.isArray(loopRangeType)) boxType(asmElementType) else asmElementType
v.load(arrayVar, OBJECT_TYPE)
v.load(indexVar, Type.INT_TYPE)
v.aload(arrayElParamType)
StackValue.onStack(arrayElParamType).put(asmElementType, codegen.v)
v.store(loopParameterVar, asmElementType)
}
override fun increment(loopExit: Label) {
v.iinc(indexVar, 1)
}
}
@@ -0,0 +1,32 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.codegen.forLoop
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
class ForInCharSequenceIndicesRangeLoopGenerator(
codegen: ExpressionCodegen,
forExpression: KtForExpression,
loopRangeCall: ResolvedCall<*>
) : ForInOptimizedIndicesLoopGenerator(codegen, forExpression, loopRangeCall) {
override fun getReceiverSizeAsInt() {
v.invokeinterface("java/lang/CharSequence", "length", "()I")
}
}
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.codegen.forLoop
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
class ForInCollectionIndicesRangeLoopGenerator(
codegen: ExpressionCodegen,
forExpression: KtForExpression,
loopRangeCall: ResolvedCall<*>
) : ForInOptimizedIndicesLoopGenerator(codegen, forExpression, loopRangeCall) {
override fun getReceiverSizeAsInt() {
v.invokeinterface("java/util/Collection", "size", "()I")
}
}
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.codegen.forLoop
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
class ForInDownToProgressionLoopGenerator(
codegen: ExpressionCodegen,
forExpression: KtForExpression,
loopRangeCall: ResolvedCall<*>
) : AbstractForInRangeLoopGenerator(codegen, forExpression, -1) {
private val from: ReceiverValue = loopRangeCall.extensionReceiver!!
private val to: KtExpression = ExpressionCodegen.getSingleArgumentExpression(loopRangeCall)!!
override fun storeRangeStartAndEnd() {
loopParameter().store(codegen.generateReceiverValue(from, false), v)
StackValue.local(endVar, asmElementType).store(codegen.gen(to), v)
}
}
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.codegen.forLoop
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Type
abstract class ForInOptimizedIndicesLoopGenerator(
codegen: ExpressionCodegen,
forExpression: KtForExpression,
loopRangeCall: ResolvedCall<*>
) : AbstractForInRangeLoopGenerator(codegen, forExpression) {
protected val receiverValue: ReceiverValue = loopRangeCall.extensionReceiver!!
protected val expectedReceiverType: KotlinType = ExpressionCodegen.getExpectedReceiverType(loopRangeCall)
override fun storeRangeStartAndEnd() {
loopParameter().store(StackValue.constant(0, asmElementType), codegen.v)
val receiver = codegen.generateReceiverValue(receiverValue, false)
val receiverType = codegen.asmType(expectedReceiverType)
receiver.put(receiverType, codegen.v)
getReceiverSizeAsInt()
codegen.v.iconst(1)
codegen.v.sub(Type.INT_TYPE)
StackValue.local(endVar, asmElementType).store(StackValue.onStack(Type.INT_TYPE), codegen.v)
}
/**
* `(receiver -> size:I)`
*/
protected abstract fun getReceiverSizeAsInt()
}
@@ -0,0 +1,109 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.codegen.forLoop
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
class ForInProgressionExpressionLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression)
: AbstractForInProgressionOrRangeLoopGenerator(codegen, forExpression)
{
private var incrementVar: Int = 0
private var incrementType: Type? = null
override fun beforeLoop() {
super.beforeLoop()
incrementVar = createLoopTempVariable(asmElementType)
val loopRangeType = bindingContext.getType(forExpression.loopRange!!)!!
val asmLoopRangeType = codegen.asmType(loopRangeType)
val incrementProp = loopRangeType.memberScope.getContributedVariables(Name.identifier("step"), NoLookupLocation.FROM_BACKEND)
assert(incrementProp.size == 1) { loopRangeType.toString() + " " + incrementProp.size }
incrementType = codegen.asmType(incrementProp.iterator().next().type)
codegen.gen(forExpression.loopRange, asmLoopRangeType)
v.dup()
v.dup()
generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterType,
loopParameterVar)
generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, asmElementType, endVar)
generateRangeOrProgressionProperty(asmLoopRangeType, "getStep", incrementType!!, incrementType!!, incrementVar)
}
override fun checkEmptyLoop(loopExit: Label) {
loopParameter().put(asmElementType, v)
v.load(endVar, asmElementType)
v.load(incrementVar, incrementType!!)
val negativeIncrement = Label()
val afterIf = Label()
if (asmElementType.sort == Type.LONG) {
v.lconst(0L)
v.lcmp()
v.ifle(negativeIncrement) // if increment < 0, jump
// increment > 0
v.lcmp()
v.ifgt(loopExit)
v.goTo(afterIf)
// increment < 0
v.mark(negativeIncrement)
v.lcmp()
v.iflt(loopExit)
v.mark(afterIf)
}
else {
v.ifle(negativeIncrement) // if increment < 0, jump
// increment > 0
v.ificmpgt(loopExit)
v.goTo(afterIf)
// increment < 0
v.mark(negativeIncrement)
v.ificmplt(loopExit)
v.mark(afterIf)
}
}
override fun assignToLoopParameter() {}
override fun increment(loopExit: Label) {
checkPostCondition(loopExit)
val loopParameter = loopParameter()
loopParameter.put(asmElementType, v)
v.load(incrementVar, asmElementType)
v.add(asmElementType)
if (asmElementType === Type.BYTE_TYPE || asmElementType === Type.SHORT_TYPE || asmElementType === Type.CHAR_TYPE) {
StackValue.coerce(Type.INT_TYPE, asmElementType, v)
}
loopParameter.store(StackValue.onStack(asmElementType), v)
}
}
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.codegen.forLoop
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.psi.KtForExpression
class ForInRangeInstanceLoopGenerator(
codegen: ExpressionCodegen,
forExpression: KtForExpression
) : AbstractForInRangeLoopGenerator(codegen, forExpression) {
override fun storeRangeStartAndEnd() {
val loopRangeType = codegen.bindingContext.getType(forExpression.loopRange!!)!!
val asmLoopRangeType = codegen.asmType(loopRangeType)
codegen.gen(forExpression.loopRange, asmLoopRangeType)
v.dup()
// ranges inherit first and last from corresponding progressions
generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterType,
loopParameterVar)
generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, asmElementType, endVar)
}
}
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.codegen.forLoop
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
class ForInRangeLiteralLoopGenerator(
codegen: ExpressionCodegen,
forExpression: KtForExpression,
loopRangeCall: ResolvedCall<*>
) : AbstractForInRangeLoopGenerator(codegen, forExpression) {
private val from: ReceiverValue = loopRangeCall.dispatchReceiver!!
private val to: KtExpression = ExpressionCodegen.getSingleArgumentExpression(loopRangeCall)!!
override fun storeRangeStartAndEnd() {
loopParameter().store(codegen.generateReceiverValue(from, false), codegen.v)
StackValue.local(endVar, asmElementType).store(codegen.gen(to), codegen.v)
}
}
@@ -0,0 +1,90 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.codegen.forLoop
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.RangeCodegenUtil
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.org.objectweb.asm.Type
fun ExpressionCodegen.getForLoopGenerator(forExpression: KtForExpression) : AbstractForLoopGenerator {
getLoopRangeResolvedCall(forExpression, bindingContext)?.let { loopRangeCall ->
createOptimizedForLoopGeneratorOrNull(forExpression, loopRangeCall)?.let {
return it
}
}
val loopRange = forExpression.loopRange!!
val loopRangeType = bindingContext.getType(loopRange)!!
val asmLoopRangeType = asmType(loopRangeType)
return when {
asmLoopRangeType.sort == Type.ARRAY ->
ForInArrayLoopGenerator(this, forExpression)
RangeCodegenUtil.isRange(loopRangeType) ->
ForInRangeInstanceLoopGenerator(this, forExpression)
RangeCodegenUtil.isProgression(loopRangeType) ->
ForInProgressionExpressionLoopGenerator(this, forExpression)
else ->
IteratorForLoopGenerator(this, forExpression)
}
}
private fun ExpressionCodegen.createOptimizedForLoopGeneratorOrNull(
forExpression: KtForExpression,
loopRangeCall: ResolvedCall<out CallableDescriptor>
): AbstractForLoopGenerator? {
val loopRangeCallee = loopRangeCall.resultingDescriptor
return when {
RangeCodegenUtil.isPrimitiveNumberRangeTo(loopRangeCallee) ->
ForInRangeLiteralLoopGenerator(this, forExpression, loopRangeCall)
RangeCodegenUtil.isPrimitiveNumberDownTo(loopRangeCallee) ->
ForInDownToProgressionLoopGenerator(this, forExpression, loopRangeCall)
RangeCodegenUtil.isArrayOrPrimitiveArrayIndices(loopRangeCallee) ->
ForInArrayIndicesRangeLoopGenerator(this, forExpression, loopRangeCall)
RangeCodegenUtil.isCollectionIndices(loopRangeCallee) ->
ForInCollectionIndicesRangeLoopGenerator(this, forExpression, loopRangeCall)
RangeCodegenUtil.isCharSequenceIndices(loopRangeCallee) ->
ForInCharSequenceIndicesRangeLoopGenerator(this, forExpression, loopRangeCall)
else -> null
}
}
private fun getLoopRangeResolvedCall(forExpression: KtForExpression, bindingContext: BindingContext): ResolvedCall<out CallableDescriptor>? {
val loopRange = KtPsiUtil.deparenthesize(forExpression.loopRange)
if (loopRange is KtQualifiedExpression) {
val qualifiedExpression = loopRange as KtQualifiedExpression?
val selector = qualifiedExpression!!.selectorExpression
if (selector is KtCallExpression || selector is KtSimpleNameExpression) {
return selector.getResolvedCall(bindingContext)
}
}
else if (loopRange is KtSimpleNameExpression || loopRange is KtCallExpression) {
return loopRange.getResolvedCall(bindingContext)
}
else if (loopRange is KtBinaryExpression) {
return loopRange.operationReference.getResolvedCall(bindingContext)
}
return null
}
@@ -0,0 +1,87 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.codegen.forLoop
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.resolve.BindingContext.*
import org.jetbrains.kotlin.resolve.BindingContextUtils.getNotNull
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
class IteratorForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression)
: AbstractForLoopGenerator(codegen, forExpression)
{
private var iteratorVarIndex: Int = 0
private val iteratorCall: ResolvedCall<FunctionDescriptor>
private val nextCall: ResolvedCall<FunctionDescriptor>
private val asmTypeForIterator: Type
init {
val loopRange = forExpression.loopRange!!
this.iteratorCall = getNotNull(bindingContext,
LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange,
"No .iterator() function " + DiagnosticUtils.atLocation(loopRange))
val iteratorType = iteratorCall.resultingDescriptor.returnType!!
this.asmTypeForIterator = codegen.asmType(iteratorType)
this.nextCall = getNotNull(bindingContext,
LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange,
"No next() function " + DiagnosticUtils.atLocation(loopRange))
}
override fun beforeLoop() {
super.beforeLoop()
// Iterator<E> tmp<iterator> = c.iterator()
iteratorVarIndex = createLoopTempVariable(asmTypeForIterator)
StackValue.local(iteratorVarIndex, asmTypeForIterator).store(codegen.invokeFunction(iteratorCall, StackValue.none()), v)
}
override fun checkEmptyLoop(loopExit: Label) {}
override fun checkPreCondition(loopExit: Label) {
// tmp<iterator>.hasNext()
val loopRange = forExpression.loopRange
val hasNextCall = getNotNull(
codegen.bindingContext, LOOP_RANGE_HAS_NEXT_RESOLVED_CALL,
loopRange!!,
"No hasNext() function " + DiagnosticUtils.atLocation(loopRange)
)
val fakeCall = codegen.makeFakeCall(TransientReceiver(iteratorCall.resultingDescriptor.returnType!!))
val result = codegen.invokeFunction(fakeCall, hasNextCall, StackValue.local(iteratorVarIndex, asmTypeForIterator))
result.put(Type.BOOLEAN_TYPE, v)
v.ifeq(loopExit)
}
override fun assignToLoopParameter() {
val fakeCall = codegen.makeFakeCall(TransientReceiver(iteratorCall.resultingDescriptor.returnType!!))
val value = codegen.invokeFunction(fakeCall, nextCall, StackValue.local(iteratorVarIndex, asmTypeForIterator))
StackValue.local(loopParameterVar, loopParameterType).store(value, v)
}
override fun increment(loopExit: Label) {}
}