Move for-loop generators out of ExpressionCodegen, convert them to Kotlin
This commit is contained in:
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegen;
|
|||||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.ResolvedCallWithRealDescriptor;
|
import org.jetbrains.kotlin.codegen.coroutines.ResolvedCallWithRealDescriptor;
|
||||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
|
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
|
||||||
|
import org.jetbrains.kotlin.codegen.forLoop.*;
|
||||||
import org.jetbrains.kotlin.codegen.inline.*;
|
import org.jetbrains.kotlin.codegen.inline.*;
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.*;
|
import org.jetbrains.kotlin.codegen.intrinsics.*;
|
||||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsKt;
|
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.LocalVariableDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
|
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
|
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
|
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||||
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
|
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
|
||||||
@@ -422,7 +421,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private Type asmType(@NotNull KotlinType type) {
|
public Type asmType(@NotNull KotlinType type) {
|
||||||
return typeMapper.mapType(type);
|
return typeMapper.mapType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -605,68 +604,18 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void generateFor(@NotNull KtForExpression forExpression) {
|
private void generateFor(@NotNull KtForExpression forExpression) {
|
||||||
ResolvedCall<? extends CallableDescriptor> loopRangeCall = RangeCodegenUtil.getLoopRangeResolvedCall(forExpression, bindingContext);
|
generateForLoop(ForLoopGeneratorsKt.getForLoopGenerator(this, forExpression));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static KotlinType getExpectedReceiverType(@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall) {
|
public static KotlinType getExpectedReceiverType(@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall) {
|
||||||
ReceiverParameterDescriptor extensionReceiver = resolvedCall.getResultingDescriptor().getExtensionReceiverParameter();
|
ReceiverParameterDescriptor extensionReceiver = resolvedCall.getResultingDescriptor().getExtensionReceiverParameter();
|
||||||
assert extensionReceiver != null : "Extension receiver should be non-null";
|
assert extensionReceiver != null : "Extension receiver should be non-null";
|
||||||
return extensionReceiver.getType();
|
return extensionReceiver.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static KtExpression getSingleArgumentExpression(@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall) {
|
public static KtExpression getSingleArgumentExpression(@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall) {
|
||||||
List<ResolvedValueArgument> resolvedValueArguments = resolvedCall.getValueArgumentsByIndex();
|
List<ResolvedValueArgument> resolvedValueArguments = resolvedCall.getValueArgumentsByIndex();
|
||||||
if (resolvedValueArguments == null) return null;
|
if (resolvedValueArguments == null) return null;
|
||||||
if (resolvedValueArguments.size() != 1) return null;
|
if (resolvedValueArguments.size() != 1) return null;
|
||||||
@@ -694,7 +643,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
PseudoInsnsKt.fakeAlwaysFalseIfeq(v, continueLabel);
|
PseudoInsnsKt.fakeAlwaysFalseIfeq(v, continueLabel);
|
||||||
|
|
||||||
generator.beforeBody();
|
generator.beforeBody();
|
||||||
blockStackElements.push(new LoopBlockStackElement(loopExit, continueLabel, targetLabel(generator.forExpression)));
|
blockStackElements.push(new LoopBlockStackElement(loopExit, continueLabel, targetLabel(generator.getForExpression())));
|
||||||
generator.body();
|
generator.body();
|
||||||
blockStackElements.pop();
|
blockStackElements.pop();
|
||||||
v.mark(continueLabel);
|
v.mark(continueLabel);
|
||||||
@@ -706,616 +655,12 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
generator.afterLoop();
|
generator.afterLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private abstract class AbstractForLoopGenerator {
|
public void generateLoopBody(@Nullable KtExpression body) {
|
||||||
|
|
||||||
// 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) {
|
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
gen(body, Type.VOID_TYPE);
|
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
|
@Override
|
||||||
public StackValue visitBreakExpression(@NotNull KtBreakExpression expression, StackValue receiver) {
|
public StackValue visitBreakExpression(@NotNull KtBreakExpression expression, StackValue receiver) {
|
||||||
@@ -4187,7 +3532,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private VariableDescriptor getVariableDescriptorNotNull(@NotNull KtElement declaration) {
|
public VariableDescriptor getVariableDescriptorNotNull(@NotNull KtElement declaration) {
|
||||||
VariableDescriptor descriptor = bindingContext.get(VARIABLE, declaration);
|
VariableDescriptor descriptor = bindingContext.get(VARIABLE, declaration);
|
||||||
assert descriptor != null : "Couldn't find variable declaration in binding context " + declaration.getText();
|
assert descriptor != null : "Couldn't find variable declaration in binding context " + declaration.getText();
|
||||||
return descriptor;
|
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");
|
KtSimpleNameExpression fake = KtPsiFactoryKt.KtPsiFactory(state.getProject(), false).createSimpleName("fake");
|
||||||
return CallMaker.makeCall(fake, initializerAsReceiver);
|
return CallMaker.makeCall(fake, initializerAsReceiver);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,27 +74,6 @@ public class RangeCodegenUtil {
|
|||||||
return !rangeType.isMarkedNullable() && getPrimitiveProgressionElementType(rangeType) != null;
|
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
|
@Nullable
|
||||||
private static PrimitiveType getPrimitiveRangeElementType(KotlinType rangeType) {
|
private static PrimitiveType getPrimitiveRangeElementType(KotlinType rangeType) {
|
||||||
return getPrimitiveRangeOrProgressionElementType(rangeType, RANGE_TO_ELEMENT_TYPE);
|
return getPrimitiveRangeOrProgressionElementType(rangeType, RANGE_TO_ELEMENT_TYPE);
|
||||||
|
|||||||
+69
@@ -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 }
|
||||||
|
}
|
||||||
+82
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+161
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+31
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
@@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
+31
@@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
+38
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+51
@@ -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()
|
||||||
|
}
|
||||||
+109
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+38
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+38
@@ -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) {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user