From c83a5b8bd5eee259605e234b0bc868dc65561476 Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Wed, 30 Sep 2015 14:23:38 +0300 Subject: [PATCH] Proper param propagation in inline --- .../kotlin/codegen/ArgumentGenerator.kt | 24 +-- .../codegen/CallBasedArgumentGenerator.java | 12 +- .../kotlin/codegen/CallGenerator.java | 124 ---------------- .../jetbrains/kotlin/codegen/CallGenerator.kt | 138 ++++++++++++++++++ .../codegen/ImplementationBodyCodegen.java | 5 + .../codegen/inline/CapturedParamInfo.java | 4 +- .../kotlin/codegen/inline/InlineCodegen.java | 50 +++++-- .../codegen/inline/LocalVarRemapper.java | 37 +++-- .../kotlin/codegen/inline/MethodInliner.java | 2 +- .../kotlin/codegen/inline/ParameterInfo.java | 25 +++- .../kotlin/codegen/inline/Parameters.java | 34 +++++ .../codegen/inline/ParametersBuilder.kt | 57 +++++--- .../boxInline/argumentOrder/justLambda.1.kt | 19 +++ .../boxInline/argumentOrder/justLambda.2.kt | 5 + .../boxInline/argumentOrder/simple.1.kt | 19 +++ .../boxInline/argumentOrder/simple.2.kt | 5 + .../BlackBoxInlineCodegenTestGenerated.java | 21 +++ ...otlinAgainstInlineKotlinTestGenerated.java | 21 +++ 18 files changed, 409 insertions(+), 193 deletions(-) delete mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.java create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt create mode 100644 compiler/testData/codegen/boxInline/argumentOrder/justLambda.1.kt create mode 100644 compiler/testData/codegen/boxInline/argumentOrder/justLambda.2.kt create mode 100644 compiler/testData/codegen/boxInline/argumentOrder/simple.1.kt create mode 100644 compiler/testData/codegen/boxInline/argumentOrder/simple.2.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ArgumentGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/ArgumentGenerator.kt index 66e6a90b156..a26ee863945 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ArgumentGenerator.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ArgumentGenerator.kt @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.utils.mapToIndex import org.jetbrains.org.objectweb.asm.Type import java.util.* -private class ArgumentAndIndex(val arg: ResolvedValueArgument, val declIndex: Int, var type: Type? = null, var reoder: Boolean = false, var tempValue: StackValue? = null) +class ArgumentAndIndex(val arg: ResolvedValueArgument, val declIndex: Int, var type: Type? = null, var reorder: Boolean = false, var tempValue: StackValue? = null) abstract class ArgumentGenerator { /** @@ -78,26 +78,12 @@ abstract class ArgumentGenerator { if (actualIndex != declIndex || orderChanged) { orderChanged = true - argumentWithDeclIndex.reoder = true + argumentWithDeclIndex.reorder = true } } - val mark = codegen.myFrameMap.mark() - actualArgsWithDeclIndex.reversed().forEach { - if (it.reoder) { - val type = it.type!! - it.tempValue = StackValue.local(codegen.frameMap.enterTemp(type), type) - it.tempValue?.store(StackValue.onStack(type), codegen.v) - } - } + reorderArgumentsIfNeeded(actualArgsWithDeclIndex) - actualArgsWithDeclIndex.sortedBy { it.declIndex }.forEach { - it.tempValue?.let { - it.put(it.type, codegen.v) - } - } - - mark.dropTo() return masks } @@ -116,4 +102,8 @@ abstract class ArgumentGenerator { protected open fun generateOther(i: Int, argument: ResolvedValueArgument): Type { throw UnsupportedOperationException("Unsupported value argument #$i: $argument") } + + protected open fun reorderArgumentsIfNeeded(args: ArrayList) { + throw UnsupportedOperationException("Unsupported operation") + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java index c399ef60af4..34d243ddf34 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.psi.ValueArgument; import org.jetbrains.kotlin.resolve.calls.model.*; import org.jetbrains.org.objectweb.asm.Type; +import java.util.ArrayList; import java.util.List; import static org.jetbrains.kotlin.codegen.AsmUtil.pushDefaultValueOnStack; @@ -72,7 +73,7 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator { assert valueArgument != null; JetExpression argumentExpression = valueArgument.getArgumentExpression(); assert argumentExpression != null : valueArgument.asElement().getText(); - callGenerator.genValueAndPut(parameter, argumentExpression, type); + callGenerator.genValueAndPut(parameter, argumentExpression, type, i); return type; } @@ -82,7 +83,7 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator { ValueParameterDescriptor parameter = valueParameters.get(i); Type type = valueParameterTypes.get(i); pushDefaultValueOnStack(type, codegen.v); - callGenerator.afterParameterPut(type, null, parameter); + callGenerator.afterParameterPut(type, null, parameter, i); return type; } @@ -92,7 +93,12 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator { ValueParameterDescriptor parameter = valueParameters.get(i); Type type = valueParameterTypes.get(i); codegen.genVarargs(argument, parameter.getType()); - callGenerator.afterParameterPut(type, null, parameter); + callGenerator.afterParameterPut(type, null, parameter, i); return type; } + + @Override + protected void reorderArgumentsIfNeeded(@NotNull ArrayList actualArgsWithDeclIndex) { + callGenerator.reorderArgumentsIfNeeded(actualArgsWithDeclIndex); + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.java deleted file mode 100644 index 17c148492a2..00000000000 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2010-2015 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; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor; -import org.jetbrains.kotlin.psi.JetExpression; -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; -import org.jetbrains.org.objectweb.asm.Type; - -public abstract class CallGenerator { - - static class DefaultCallGenerator extends CallGenerator { - - private final ExpressionCodegen codegen; - - public DefaultCallGenerator(ExpressionCodegen codegen) { - this.codegen = codegen; - } - - @Override - public void genCallInner( - @NotNull Callable callableMethod, - ResolvedCall resolvedCall, - boolean callDefault, - @NotNull ExpressionCodegen codegen - ) { - if (!callDefault) { - callableMethod.genInvokeInstruction(codegen.v); - } - else { - ((CallableMethod)callableMethod).genInvokeDefaultInstruction(codegen.v); - } - } - - @Override - public void genCallWithoutAssertions( - @NotNull CallableMethod method, @NotNull ExpressionCodegen codegen - ) { - method.genInvokeInstruction(codegen.v); - } - - @Override - public void afterParameterPut(@NotNull Type type, StackValue stackValue, @NotNull ValueParameterDescriptor valueParameterDescriptor) { - - } - - @Override - public void putHiddenParams() { - - } - - @Override - public void genValueAndPut( - @NotNull ValueParameterDescriptor valueParameterDescriptor, - @NotNull JetExpression argumentExpression, - @NotNull Type parameterType - ) { - StackValue value = codegen.gen(argumentExpression); - value.put(parameterType, codegen.v); - } - - @Override - public void putCapturedValueOnStack( - @NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex - ) { - stackValue.put(stackValue.type, codegen.v); - } - - @Override - public void putValueIfNeeded( - @Nullable ValueParameterDescriptor valueParameterDescriptor, @NotNull Type parameterType, @NotNull StackValue value - ) { - value.put(value.type, codegen.v); - } - } - - public void genCall(@NotNull Callable callableMethod, @Nullable ResolvedCall resolvedCall, boolean callDefault, @NotNull ExpressionCodegen codegen) { - if (resolvedCall != null) { - JetExpression calleeExpression = resolvedCall.getCall().getCalleeExpression(); - if (calleeExpression != null) { - codegen.markStartLineNumber(calleeExpression); - } - } - - genCallInner(callableMethod, resolvedCall, callDefault, codegen); - } - - public abstract void genCallInner(@NotNull Callable callableMethod, @Nullable ResolvedCall resolvedCall, boolean callDefault, @NotNull ExpressionCodegen codegen); - - public abstract void genCallWithoutAssertions(@NotNull CallableMethod callableMethod, @NotNull ExpressionCodegen codegen); - - public abstract void afterParameterPut(@NotNull Type type, StackValue stackValue, @NotNull ValueParameterDescriptor valueParameterDescriptor); - - public abstract void genValueAndPut( - @NotNull ValueParameterDescriptor valueParameterDescriptor, - @NotNull JetExpression argumentExpression, - @NotNull Type parameterType - ); - - public abstract void putValueIfNeeded(@Nullable ValueParameterDescriptor valueParameterDescriptor, @NotNull Type parameterType, @NotNull StackValue value); - - public abstract void putCapturedValueOnStack( - @NotNull StackValue stackValue, - @NotNull Type valueType, int paramIndex - ); - - public abstract void putHiddenParams(); -} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt new file mode 100644 index 00000000000..91d60a607df --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt @@ -0,0 +1,138 @@ +/* + * Copyright 2010-2015 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 + +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.psi.JetExpression +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.org.objectweb.asm.Type + +import java.util.ArrayList + +abstract class CallGenerator { + + internal class DefaultCallGenerator(private val codegen: ExpressionCodegen) : CallGenerator() { + + override fun genCallInner( + callableMethod: Callable, + resolvedCall: ResolvedCall<*>?, + callDefault: Boolean, + codegen: ExpressionCodegen) { + if (!callDefault) { + callableMethod.genInvokeInstruction(codegen.v) + } + else { + (callableMethod as CallableMethod).genInvokeDefaultInstruction(codegen.v) + } + } + + override fun genCallWithoutAssertions( + method: CallableMethod, codegen: ExpressionCodegen) { + method.genInvokeInstruction(codegen.v) + } + + override fun afterParameterPut( + type: Type, + stackValue: StackValue?, + valueParameterDescriptor: ValueParameterDescriptor, + parameterIndex: Int) { + + } + + override fun putHiddenParams() { + + } + + override fun genValueAndPut( + valueParameterDescriptor: ValueParameterDescriptor, + argumentExpression: JetExpression, + parameterType: Type, + index: Int) { + val value = codegen.gen(argumentExpression) + value.put(parameterType, codegen.v) + } + + override fun putCapturedValueOnStack( + stackValue: StackValue, valueType: Type, paramIndex: Int) { + stackValue.put(stackValue.type, codegen.v) + } + + override fun putValueIfNeeded( + valueParameterDescriptor: ValueParameterDescriptor?, parameterType: Type, value: StackValue) { + value.put(value.type, codegen.v) + } + + override fun reorderArgumentsIfNeeded(actualArgsWithDeclIndex: ArrayList) { + val mark = codegen.myFrameMap.mark() + actualArgsWithDeclIndex.reversed().forEach { + if (it.reorder) { + val type = it.type!! + it.tempValue = StackValue.local(codegen.frameMap.enterTemp(type), type) + it.tempValue?.store(StackValue.onStack(type), codegen.v) + } + } + + actualArgsWithDeclIndex.sortedBy { it.declIndex }.forEach { + it.tempValue?.let { + it.put(it.type, codegen.v) + } + } + + mark.dropTo() + } + } + + fun genCall(callableMethod: Callable, resolvedCall: ResolvedCall<*>?, callDefault: Boolean, codegen: ExpressionCodegen) { + if (resolvedCall != null) { + val calleeExpression = resolvedCall.call.calleeExpression + if (calleeExpression != null) { + codegen.markStartLineNumber(calleeExpression) + } + } + + genCallInner(callableMethod, resolvedCall, callDefault, codegen) + } + + abstract fun genCallInner(callableMethod: Callable, resolvedCall: ResolvedCall<*>?, callDefault: Boolean, codegen: ExpressionCodegen) + + abstract fun genCallWithoutAssertions(callableMethod: CallableMethod, codegen: ExpressionCodegen) + + abstract fun afterParameterPut( + type: Type, + stackValue: StackValue?, + valueParameterDescriptor: ValueParameterDescriptor, + parameterIndex: Int) + + abstract fun genValueAndPut( + valueParameterDescriptor: ValueParameterDescriptor, + argumentExpression: JetExpression, + parameterType: Type, + parameterIndex: Int) + + abstract fun putValueIfNeeded( + valueParameterDescriptor: ValueParameterDescriptor?, + parameterType: Type, + value: StackValue) + + abstract fun putCapturedValueOnStack( + stackValue: StackValue, + valueType: Type, paramIndex: Int) + + abstract fun putHiddenParams() + + abstract fun reorderArgumentsIfNeeded(actualArgsWithDeclIndex: ArrayList) +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 0cbef0df19d..f9363628cb9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -1669,6 +1669,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { offset += type.getSize(); return type; } + + @Override + protected void reorderArgumentsIfNeeded(@NotNull ArrayList args) { + + } } private void generateEnumEntries() { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CapturedParamInfo.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CapturedParamInfo.java index ba32c51329b..8269a11178f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CapturedParamInfo.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CapturedParamInfo.java @@ -38,13 +38,13 @@ public class CapturedParamInfo extends ParameterInfo { } public CapturedParamInfo(@NotNull CapturedParamDesc desc, @NotNull String newFieldName, boolean skipped, int index, int remapIndex) { - super(desc.getType(), skipped, index, remapIndex); + super(desc.getType(), skipped, index, remapIndex, index); this.desc = desc; this.newFieldName = newFieldName; } public CapturedParamInfo(@NotNull CapturedParamDesc desc, @NotNull String newFieldName, boolean skipped, int index, StackValue remapIndex) { - super(desc.getType(), skipped, index, remapIndex); + super(desc.getType(), skipped, index, remapIndex, index); this.desc = desc; this.newFieldName = newFieldName; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index 05bf5bf7170..096d8c7ebe8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -410,14 +410,20 @@ public class InlineCodegen extends CallGenerator { } @Override - public void afterParameterPut(@NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor) { - putArgumentOrCapturedToLocalVal(type, stackValue, -1); + public void afterParameterPut( + @NotNull Type type, + @Nullable StackValue stackValue, + @Nullable ValueParameterDescriptor valueParameterDescriptor, + int parameterIndex + ) { + putArgumentOrCapturedToLocalVal(type, stackValue, -1, parameterIndex); } private void putArgumentOrCapturedToLocalVal( @NotNull Type type, @Nullable StackValue stackValue, - int capturedParamIndex + int capturedParamIndex, + int parameterIndex ) { if (!asFunctionInline && Type.VOID_TYPE != type) { //TODO remap only inlinable closure => otherwise we could get a lot of problem @@ -431,7 +437,7 @@ public class InlineCodegen extends CallGenerator { info.setRemapValue(remappedIndex); } else { - info = invocationParamBuilder.addNextParameter(type, false, remappedIndex); + info = invocationParamBuilder.addNextValueParameter(type, false, remappedIndex, parameterIndex); } recordParameterValueInLocalVal(info); @@ -513,6 +519,7 @@ public class InlineCodegen extends CallGenerator { invocationParamBuilder.addNextParameter(param.getAsmType(), false, null); } + invocationParamBuilder.markValueParametesStart(); List infos = invocationParamBuilder.listNotCaptured(); recordParameterValueInLocalVal(infos.toArray(new ParameterInfo[infos.size()])); } @@ -542,13 +549,13 @@ public class InlineCodegen extends CallGenerator { deparenthesized instanceof JetCallableReferenceExpression; } - public void rememberClosure(JetExpression expression, Type type) { + public void rememberClosure(JetExpression expression, Type type, int parameterIndex) { JetExpression lambda = JetPsiUtil.deparenthesize(expression); assert isInlinableParameterExpression(lambda) : "Couldn't find inline expression in " + expression.getText(); LambdaInfo info = new LambdaInfo(lambda, typeMapper); - ParameterInfo closureInfo = invocationParamBuilder.addNextParameter(type, true, null); + ParameterInfo closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameterIndex); closureInfo.setLambda(info); expressionMap.put(closureInfo.getIndex(), info); } @@ -619,23 +626,37 @@ public class InlineCodegen extends CallGenerator { public void genValueAndPut( @NotNull ValueParameterDescriptor valueParameterDescriptor, @NotNull JetExpression argumentExpression, - @NotNull Type parameterType + @NotNull Type parameterType, + int parameterIndex ) { if (isInliningParameter(argumentExpression, valueParameterDescriptor)) { - rememberClosure(argumentExpression, parameterType); + rememberClosure(argumentExpression, parameterType, valueParameterDescriptor.getIndex()); } else { StackValue value = codegen.gen(argumentExpression); - putValueIfNeeded(valueParameterDescriptor, parameterType, value); + putValueIfNeeded(valueParameterDescriptor, parameterType, value, valueParameterDescriptor.getIndex()); } } @Override - public void putValueIfNeeded(@Nullable ValueParameterDescriptor valueParameterDescriptor, @NotNull Type parameterType, @NotNull StackValue value) { + public void putValueIfNeeded( + @Nullable ValueParameterDescriptor valueParameterDescriptor, + @NotNull Type parameterType, + @NotNull StackValue value + ) { + putValueIfNeeded(valueParameterDescriptor, parameterType, value, -1); + } + + private void putValueIfNeeded( + @Nullable ValueParameterDescriptor valueParameterDescriptor, + @NotNull Type parameterType, + @NotNull StackValue value, + int index + ) { if (shouldPutValue(parameterType, value)) { value.put(parameterType, codegen.v); } - afterParameterPut(parameterType, value, valueParameterDescriptor); + afterParameterPut(parameterType, value, valueParameterDescriptor, index); } @Override @@ -645,7 +666,7 @@ public class InlineCodegen extends CallGenerator { if (shouldPutValue(stackValue.type, stackValue)) { stackValue.put(stackValue.type, codegen.v); } - putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex); + putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex); } @@ -749,4 +770,9 @@ public class InlineCodegen extends CallGenerator { String targetFile = getSourceFilePath(targetDescriptor); incrementalCache.registerInline(sourceFile, jvmSignature.toString(), targetFile); } + + @Override + public void reorderArgumentsIfNeeded(@NotNull ArrayList actualArgsWithDeclIndex) { + + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LocalVarRemapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LocalVarRemapper.java index 404d87c0e82..6e6a34c2001 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LocalVarRemapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LocalVarRemapper.java @@ -34,7 +34,6 @@ public class LocalVarRemapper { private final int actualParamsSize; private final StackValue[] remapValues; - private final int additionalShift; public LocalVarRemapper(Parameters params, int additionalShift) { @@ -42,20 +41,40 @@ public class LocalVarRemapper { this.allParamsSize = params.totalSize(); this.params = params; - int realSize = 0; remapValues = new StackValue [params.totalSize()]; + Integer [] declIndexesToActual = new Integer [params.totalSize()]; + Integer [] actualDeclShifts = new Integer [params.totalSize()]; int index = 0; - for (ParameterInfo info : params) { - if (!info.isSkippedOrRemapped()) { - remapValues[index] = StackValue.local(realSize, AsmTypes.OBJECT_TYPE); - realSize += info.getType().getSize(); - } else { - remapValues[index] = info.isRemapped() ? info.getRemapValue() : null; + for (ParameterInfo param : params) { + if (param != ParameterInfo.STUB && param != CapturedParamInfo.STUB) { + declIndexesToActual[param.declarationIndex] = index; } index++; } + int realSize = 0; + for (int i = 0; i < declIndexesToActual.length; i++) { + Integer declIndexToActual = declIndexesToActual[i]; + if (declIndexToActual != null) { + actualDeclShifts[i] = realSize; + realSize += params.get(declIndexToActual).getType().getSize(); + } + } + + realSize = 0; + for (ParameterInfo info : params) { + if (info != ParameterInfo.STUB && info != CapturedParamInfo.STUB) { + if (!info.isSkippedOrRemapped()) { + remapValues[actualDeclShifts[info.declarationIndex]] = StackValue.local(realSize, AsmTypes.OBJECT_TYPE); + realSize += info.getType().getSize(); + } + else { + remapValues[actualDeclShifts[info.declarationIndex]] = info.isRemapped() ? info.getRemapValue() : null; + } + } + } + actualParamsSize = realSize; } @@ -63,7 +82,7 @@ public class LocalVarRemapper { int remappedIndex; if (index < allParamsSize) { - ParameterInfo info = params.get(index); + ParameterInfo info = params.getByByteCodeIndex(index); StackValue remapped = remapValues[index]; if (info.isSkipped || remapped == null) { return new RemapInfo(info); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java index f6e7c36e2a3..401223b5e3e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java @@ -559,7 +559,7 @@ public class MethodInliner { private LambdaInfo getLambdaIfExists(int varIndex) { if (varIndex < parameters.totalSize()) { - return parameters.get(varIndex).getLambda(); + return parameters.getByByteCodeIndex(varIndex).getLambda(); } return null; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParameterInfo.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParameterInfo.java index 2580d048731..e4d15e372d5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParameterInfo.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParameterInfo.java @@ -24,31 +24,34 @@ import org.jetbrains.org.objectweb.asm.Type; class ParameterInfo { - public static final ParameterInfo STUB = new ParameterInfo(AsmTypes.OBJECT_TYPE, true, -1, -1); + public static final ParameterInfo STUB = new ParameterInfo(AsmTypes.OBJECT_TYPE, true, -1, -1, -1); protected final int index; + protected final int declarationIndex; + private boolean isCaptured; public final Type type; //for skipped parameter: e.g. inlined lambda - public final boolean isSkipped; + public boolean isSkipped; //in case when parameter could be extracted from outer context (e.g. from local var) private StackValue remapValue; public LambdaInfo lambda; - ParameterInfo(Type type, boolean skipped, int index, int remapValue) { - this(type, skipped, index, remapValue == -1 ? null : StackValue.local(remapValue, type)); + ParameterInfo(Type type, boolean skipped, int index, int remapValue, int declarationIndex) { + this(type, skipped, index, remapValue == -1 ? null : StackValue.local(remapValue, type), declarationIndex); } - ParameterInfo(@NotNull Type type, boolean skipped, int index, @Nullable StackValue remapValue) { + ParameterInfo(@NotNull Type type, boolean skipped, int index, @Nullable StackValue remapValue, int declarationIndex) { this.type = type; this.isSkipped = skipped; this.remapValue = remapValue; this.index = index; + this.declarationIndex = declarationIndex; } public boolean isSkippedOrRemapped() { @@ -82,19 +85,27 @@ class ParameterInfo { return lambda; } - public void setLambda(@Nullable LambdaInfo lambda) { + public ParameterInfo setLambda(@Nullable LambdaInfo lambda) { this.lambda = lambda; + return this; } - public void setRemapValue(StackValue remapValue) { + public ParameterInfo setRemapValue(StackValue remapValue) { this.remapValue = remapValue; + return this; } public boolean isCaptured() { return isCaptured; } + public ParameterInfo setSkipped(boolean skipped) { + isSkipped = skipped; + return this; + } + public void setCaptured(boolean isCaptured) { this.isCaptured = isCaptured; } + } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/Parameters.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/Parameters.java index 792d952473a..11d17db240d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/Parameters.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/Parameters.java @@ -29,9 +29,32 @@ public class Parameters implements Iterable { private final List real; private final List captured; + private final Integer [] declIndexesToActual; + private final ParameterInfo [] actualDeclShifts; + public Parameters(List real, List captured) { this.real = real; this.captured = captured; + + declIndexesToActual = new Integer [totalSize()]; + + int index = 0; + for (ParameterInfo param : this) { + if (param != ParameterInfo.STUB && param != CapturedParamInfo.STUB) { + declIndexesToActual[param.declarationIndex] = index; + } + index++; + } + + actualDeclShifts = new ParameterInfo [totalSize()]; + int realSize = 0; + for (int i = 0; i < declIndexesToActual.length; i++) { + Integer declIndexToActual = declIndexesToActual[i]; + if (declIndexToActual != null) { + actualDeclShifts[realSize] = getByDeclarationIndex(i); + realSize += get(declIndexToActual).getType().getSize(); + } + } } public List getReal() { @@ -46,6 +69,17 @@ public class Parameters implements Iterable { return real.size() + captured.size(); } + public ParameterInfo getByDeclarationIndex(int index) { + if (index < real.size()) { + return real.get(declIndexesToActual[index]); + } + return captured.get(index - real.size()); + } + + public ParameterInfo getByByteCodeIndex(int index) { + return actualDeclShifts[index]; + } + public ParameterInfo get(int index) { if (index < real.size()) { return real.get(index); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParametersBuilder.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParametersBuilder.kt index 47033046fb2..8094d72fe5b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParametersBuilder.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParametersBuilder.kt @@ -22,43 +22,54 @@ import org.jetbrains.org.objectweb.asm.Type import java.util.ArrayList import java.util.Collections -class ParametersBuilder { +class ParametersBuilder private constructor(){ - private val params = ArrayList() - private val capturedParams = ArrayList() + private val valueAndHiddenParams = arrayListOf() + private val capturedParams = arrayListOf() + private var valueParamStart = 0 var nextValueParameterIndex = 0 private set + private var nextCaptured = 0 fun addThis(type: Type, skipped: Boolean): ParameterInfo { - val info = ParameterInfo(type, skipped, nextValueParameterIndex, -1) + val info = ParameterInfo(type, skipped, nextValueParameterIndex, -1, valueAndHiddenParams.size()) addParameter(info) return info } fun addNextParameter(type: Type, skipped: Boolean, remapValue: StackValue?): ParameterInfo { - return addParameter(ParameterInfo(type, skipped, nextValueParameterIndex, remapValue)) + return addParameter(ParameterInfo(type, skipped, nextValueParameterIndex, remapValue, valueAndHiddenParams.size())) + } + + fun addNextValueParameter(type: Type, skipped: Boolean, remapValue: StackValue?, parameterIndex: Int): ParameterInfo { + return addParameter(ParameterInfo(type, skipped, nextValueParameterIndex, remapValue, + if (parameterIndex == -1) valueAndHiddenParams.size() else { parameterIndex + valueParamStart })) } fun addCapturedParam( original: CapturedParamInfo, newFieldName: String): CapturedParamInfo { - val info = CapturedParamInfo(original.desc, newFieldName, original.isSkipped, nextCaptured, original.getIndex()) + val info = CapturedParamInfo(original.desc, newFieldName, original.isSkipped, nextCapturedIndex(), original.getIndex()) info.setLambda(original.getLambda()) return addCapturedParameter(info) } + private fun nextCapturedIndex(): Int { + return nextCaptured + } + fun addCapturedParam( desc: CapturedParamDesc, newFieldName: String): CapturedParamInfo { - val info = CapturedParamInfo(desc, newFieldName, false, nextCaptured, null) + val info = CapturedParamInfo(desc, newFieldName, false, nextCapturedIndex(), null) return addCapturedParameter(info) } fun addCapturedParamCopy( copyFrom: CapturedParamInfo): CapturedParamInfo { - val info = copyFrom.newIndex(nextCaptured) + val info = copyFrom.newIndex(nextCapturedIndex()) return addCapturedParameter(info) } @@ -68,7 +79,7 @@ class ParametersBuilder { type: Type, skipped: Boolean, original: ParameterInfo?): CapturedParamInfo { - val info = CapturedParamInfo(CapturedParamDesc.createDesc(containingLambda, fieldName, type), skipped, nextCaptured, + val info = CapturedParamInfo(CapturedParamDesc.createDesc(containingLambda, fieldName, type), skipped, nextCapturedIndex(), if (original != null) original.getIndex() else -1) if (original != null) { info.setLambda(original.getLambda()) @@ -77,7 +88,7 @@ class ParametersBuilder { } private fun addParameter(info: ParameterInfo): ParameterInfo { - params.add(info) + valueAndHiddenParams.add(info) nextValueParameterIndex += info.getType().size return info } @@ -89,7 +100,11 @@ class ParametersBuilder { } fun listNotCaptured(): List { - return Collections.unmodifiableList(params) + return Collections.unmodifiableList(valueAndHiddenParams) + } + + fun markValueParametesStart(){ + this.valueParamStart = valueAndHiddenParams.size() } fun listCaptured(): List { @@ -97,9 +112,7 @@ class ParametersBuilder { } fun listAllParams(): List { - val list = ArrayList(params) - list.addAll(capturedParams) - return list + return valueAndHiddenParams + capturedParams } private fun buildWithStubs(): List { @@ -114,16 +127,24 @@ class ParametersBuilder { return Parameters(buildWithStubs(), buildCapturedWithStubs()) } +// public fun getValueParameter(index: Int): ParameterInfo { +// return valueAndHiddenParams[index + valueParamStart] +// } + companion object { - @JvmStatic fun newBuilder(): ParametersBuilder { + @JvmStatic + fun newBuilder(): ParametersBuilder { return ParametersBuilder() } - @JvmOverloads @JvmStatic fun initializeBuilderFrom(objectType: Type, descriptor: String, inlineLambda: LambdaInfo? = null): ParametersBuilder { + @JvmOverloads @JvmStatic + fun initializeBuilderFrom(objectType: Type, descriptor: String, inlineLambda: LambdaInfo? = null, addThis: Boolean = true): ParametersBuilder { val builder = newBuilder() - //skipped this for inlined lambda cause it will be removed - builder.addThis(objectType, inlineLambda != null).setLambda(inlineLambda) + if (addThis) { + //skipped this for inlined lambda cause it will be removed + builder.addThis(objectType, inlineLambda != null).setLambda(inlineLambda) + } val types = Type.getArgumentTypes(descriptor) for (type in types) { diff --git a/compiler/testData/codegen/boxInline/argumentOrder/justLambda.1.kt b/compiler/testData/codegen/boxInline/argumentOrder/justLambda.1.kt new file mode 100644 index 00000000000..cd542a8fa24 --- /dev/null +++ b/compiler/testData/codegen/boxInline/argumentOrder/justLambda.1.kt @@ -0,0 +1,19 @@ +import test.* + +fun box(): String { + var res = ""; + var call = test(a = {res += "K"; "K"}(), b = {res+="O"; "O"}(), c = {res += "L"; "L"}) + if (res != "KOL" || call != "KOL") return "fail 1: $res != KOL or $call != KOL" + + res = ""; + call = test(a = {res += "K"; "K"}(), c = {res += "L"; "L"}, b = {res+="O"; "O"}()) + if (res != "KOL" || call != "KOL") return "fail 2: $res != KOL or $call != KOL" + + + res = ""; + call = test(c = {res += "L"; "L"}, a = {res += "K"; "K"}(), b = {res+="O"; "O"}()) + if (res != "KOL" || call != "KOL") return "fail 3: $res != KOL or $call != KOL" + + return "OK" + +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/argumentOrder/justLambda.2.kt b/compiler/testData/codegen/boxInline/argumentOrder/justLambda.2.kt new file mode 100644 index 00000000000..2bbfaf5dff4 --- /dev/null +++ b/compiler/testData/codegen/boxInline/argumentOrder/justLambda.2.kt @@ -0,0 +1,5 @@ +package test + +inline fun test(a: String, b: String, c: () -> String): String { + return a + b + c(); +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/argumentOrder/simple.1.kt b/compiler/testData/codegen/boxInline/argumentOrder/simple.1.kt new file mode 100644 index 00000000000..14f10117d9e --- /dev/null +++ b/compiler/testData/codegen/boxInline/argumentOrder/simple.1.kt @@ -0,0 +1,19 @@ +import test.* + +fun box(): String { + var res = ""; + var call = test(b = {res += "K"; "K"}(), a = {res+="O"; "O"}(), c = {res += "L"; "L"}) + if (res != "KOL" || call != "OKL") return "fail 1: $res != KOL or $call != OKL" + + res = ""; + call = test(b = {res += "K"; "K"}(), c = {res += "L"; "L"}, a = {res+="O"; "O"}()) + if (res != "KOL" || call != "OKL") return "fail 2: $res != KOL or $call != OKL" + + + res = ""; + call = test(c = {res += "L"; "L"}, b = {res += "K"; "K"}(), a = {res+="O"; "O"}()) + if (res != "KOL" || call != "OKL") return "fail 3: $res != KOL or $call != OKL" + + return "OK" + +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/argumentOrder/simple.2.kt b/compiler/testData/codegen/boxInline/argumentOrder/simple.2.kt new file mode 100644 index 00000000000..2bbfaf5dff4 --- /dev/null +++ b/compiler/testData/codegen/boxInline/argumentOrder/simple.2.kt @@ -0,0 +1,5 @@ +package test + +inline fun test(a: String, b: String, c: () -> String): String { + return a + b + c(); +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java index 2a7a88830fd..a1f15398e76 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java @@ -116,6 +116,27 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo } } + @TestMetadata("compiler/testData/codegen/boxInline/argumentOrder") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ArgumentOrder extends AbstractBlackBoxInlineCodegenTest { + public void testAllFilesPresentInArgumentOrder() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/argumentOrder"), Pattern.compile("^(.+)\\.1.kt$"), true); + } + + @TestMetadata("justLambda.1.kt") + public void testJustLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/argumentOrder/justLambda.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + + @TestMetadata("simple.1.kt") + public void testSimple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/argumentOrder/simple.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/builders") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java index 873a5c4a1cc..2af3892b29e 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -116,6 +116,27 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi } } + @TestMetadata("compiler/testData/codegen/boxInline/argumentOrder") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ArgumentOrder extends AbstractCompileKotlinAgainstInlineKotlinTest { + public void testAllFilesPresentInArgumentOrder() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/argumentOrder"), Pattern.compile("^(.+)\\.1.kt$"), true); + } + + @TestMetadata("justLambda.1.kt") + public void testJustLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/argumentOrder/justLambda.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + + @TestMetadata("simple.1.kt") + public void testSimple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/argumentOrder/simple.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/builders") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)