Proper param propagation in inline

This commit is contained in:
Michael Bogdanov
2015-09-30 14:23:38 +03:00
parent 79fce388b3
commit c83a5b8bd5
18 changed files with 409 additions and 193 deletions
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.utils.mapToIndex
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import java.util.* 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 { abstract class ArgumentGenerator {
/** /**
@@ -78,26 +78,12 @@ abstract class ArgumentGenerator {
if (actualIndex != declIndex || orderChanged) { if (actualIndex != declIndex || orderChanged) {
orderChanged = true orderChanged = true
argumentWithDeclIndex.reoder = true argumentWithDeclIndex.reorder = true
} }
} }
val mark = codegen.myFrameMap.mark() reorderArgumentsIfNeeded(actualArgsWithDeclIndex)
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)
}
}
actualArgsWithDeclIndex.sortedBy { it.declIndex }.forEach {
it.tempValue?.let {
it.put(it.type, codegen.v)
}
}
mark.dropTo()
return masks return masks
} }
@@ -116,4 +102,8 @@ abstract class ArgumentGenerator {
protected open fun generateOther(i: Int, argument: ResolvedValueArgument): Type { protected open fun generateOther(i: Int, argument: ResolvedValueArgument): Type {
throw UnsupportedOperationException("Unsupported value argument #$i: $argument") throw UnsupportedOperationException("Unsupported value argument #$i: $argument")
} }
protected open fun reorderArgumentsIfNeeded(args: ArrayList<ArgumentAndIndex>) {
throw UnsupportedOperationException("Unsupported operation")
}
} }
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.psi.ValueArgument;
import org.jetbrains.kotlin.resolve.calls.model.*; import org.jetbrains.kotlin.resolve.calls.model.*;
import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.Type;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.jetbrains.kotlin.codegen.AsmUtil.pushDefaultValueOnStack; import static org.jetbrains.kotlin.codegen.AsmUtil.pushDefaultValueOnStack;
@@ -72,7 +73,7 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
assert valueArgument != null; assert valueArgument != null;
JetExpression argumentExpression = valueArgument.getArgumentExpression(); JetExpression argumentExpression = valueArgument.getArgumentExpression();
assert argumentExpression != null : valueArgument.asElement().getText(); assert argumentExpression != null : valueArgument.asElement().getText();
callGenerator.genValueAndPut(parameter, argumentExpression, type); callGenerator.genValueAndPut(parameter, argumentExpression, type, i);
return type; return type;
} }
@@ -82,7 +83,7 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
ValueParameterDescriptor parameter = valueParameters.get(i); ValueParameterDescriptor parameter = valueParameters.get(i);
Type type = valueParameterTypes.get(i); Type type = valueParameterTypes.get(i);
pushDefaultValueOnStack(type, codegen.v); pushDefaultValueOnStack(type, codegen.v);
callGenerator.afterParameterPut(type, null, parameter); callGenerator.afterParameterPut(type, null, parameter, i);
return type; return type;
} }
@@ -92,7 +93,12 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
ValueParameterDescriptor parameter = valueParameters.get(i); ValueParameterDescriptor parameter = valueParameters.get(i);
Type type = valueParameterTypes.get(i); Type type = valueParameterTypes.get(i);
codegen.genVarargs(argument, parameter.getType()); codegen.genVarargs(argument, parameter.getType());
callGenerator.afterParameterPut(type, null, parameter); callGenerator.afterParameterPut(type, null, parameter, i);
return type; return type;
} }
@Override
protected void reorderArgumentsIfNeeded(@NotNull ArrayList<ArgumentAndIndex> actualArgsWithDeclIndex) {
callGenerator.reorderArgumentsIfNeeded(actualArgsWithDeclIndex);
}
} }
@@ -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();
}
@@ -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<ArgumentAndIndex>) {
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<ArgumentAndIndex>)
}
@@ -1669,6 +1669,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
offset += type.getSize(); offset += type.getSize();
return type; return type;
} }
@Override
protected void reorderArgumentsIfNeeded(@NotNull ArrayList<ArgumentAndIndex> args) {
}
} }
private void generateEnumEntries() { private void generateEnumEntries() {
@@ -38,13 +38,13 @@ public class CapturedParamInfo extends ParameterInfo {
} }
public CapturedParamInfo(@NotNull CapturedParamDesc desc, @NotNull String newFieldName, boolean skipped, int index, int remapIndex) { 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.desc = desc;
this.newFieldName = newFieldName; this.newFieldName = newFieldName;
} }
public CapturedParamInfo(@NotNull CapturedParamDesc desc, @NotNull String newFieldName, boolean skipped, int index, StackValue remapIndex) { 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.desc = desc;
this.newFieldName = newFieldName; this.newFieldName = newFieldName;
} }
@@ -410,14 +410,20 @@ public class InlineCodegen extends CallGenerator {
} }
@Override @Override
public void afterParameterPut(@NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor) { public void afterParameterPut(
putArgumentOrCapturedToLocalVal(type, stackValue, -1); @NotNull Type type,
@Nullable StackValue stackValue,
@Nullable ValueParameterDescriptor valueParameterDescriptor,
int parameterIndex
) {
putArgumentOrCapturedToLocalVal(type, stackValue, -1, parameterIndex);
} }
private void putArgumentOrCapturedToLocalVal( private void putArgumentOrCapturedToLocalVal(
@NotNull Type type, @NotNull Type type,
@Nullable StackValue stackValue, @Nullable StackValue stackValue,
int capturedParamIndex int capturedParamIndex,
int parameterIndex
) { ) {
if (!asFunctionInline && Type.VOID_TYPE != type) { if (!asFunctionInline && Type.VOID_TYPE != type) {
//TODO remap only inlinable closure => otherwise we could get a lot of problem //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); info.setRemapValue(remappedIndex);
} }
else { else {
info = invocationParamBuilder.addNextParameter(type, false, remappedIndex); info = invocationParamBuilder.addNextValueParameter(type, false, remappedIndex, parameterIndex);
} }
recordParameterValueInLocalVal(info); recordParameterValueInLocalVal(info);
@@ -513,6 +519,7 @@ public class InlineCodegen extends CallGenerator {
invocationParamBuilder.addNextParameter(param.getAsmType(), false, null); invocationParamBuilder.addNextParameter(param.getAsmType(), false, null);
} }
invocationParamBuilder.markValueParametesStart();
List<ParameterInfo> infos = invocationParamBuilder.listNotCaptured(); List<ParameterInfo> infos = invocationParamBuilder.listNotCaptured();
recordParameterValueInLocalVal(infos.toArray(new ParameterInfo[infos.size()])); recordParameterValueInLocalVal(infos.toArray(new ParameterInfo[infos.size()]));
} }
@@ -542,13 +549,13 @@ public class InlineCodegen extends CallGenerator {
deparenthesized instanceof JetCallableReferenceExpression; deparenthesized instanceof JetCallableReferenceExpression;
} }
public void rememberClosure(JetExpression expression, Type type) { public void rememberClosure(JetExpression expression, Type type, int parameterIndex) {
JetExpression lambda = JetPsiUtil.deparenthesize(expression); JetExpression lambda = JetPsiUtil.deparenthesize(expression);
assert isInlinableParameterExpression(lambda) : "Couldn't find inline expression in " + expression.getText(); assert isInlinableParameterExpression(lambda) : "Couldn't find inline expression in " + expression.getText();
LambdaInfo info = new LambdaInfo(lambda, typeMapper); LambdaInfo info = new LambdaInfo(lambda, typeMapper);
ParameterInfo closureInfo = invocationParamBuilder.addNextParameter(type, true, null); ParameterInfo closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameterIndex);
closureInfo.setLambda(info); closureInfo.setLambda(info);
expressionMap.put(closureInfo.getIndex(), info); expressionMap.put(closureInfo.getIndex(), info);
} }
@@ -619,23 +626,37 @@ public class InlineCodegen extends CallGenerator {
public void genValueAndPut( public void genValueAndPut(
@NotNull ValueParameterDescriptor valueParameterDescriptor, @NotNull ValueParameterDescriptor valueParameterDescriptor,
@NotNull JetExpression argumentExpression, @NotNull JetExpression argumentExpression,
@NotNull Type parameterType @NotNull Type parameterType,
int parameterIndex
) { ) {
if (isInliningParameter(argumentExpression, valueParameterDescriptor)) { if (isInliningParameter(argumentExpression, valueParameterDescriptor)) {
rememberClosure(argumentExpression, parameterType); rememberClosure(argumentExpression, parameterType, valueParameterDescriptor.getIndex());
} }
else { else {
StackValue value = codegen.gen(argumentExpression); StackValue value = codegen.gen(argumentExpression);
putValueIfNeeded(valueParameterDescriptor, parameterType, value); putValueIfNeeded(valueParameterDescriptor, parameterType, value, valueParameterDescriptor.getIndex());
} }
} }
@Override @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)) { if (shouldPutValue(parameterType, value)) {
value.put(parameterType, codegen.v); value.put(parameterType, codegen.v);
} }
afterParameterPut(parameterType, value, valueParameterDescriptor); afterParameterPut(parameterType, value, valueParameterDescriptor, index);
} }
@Override @Override
@@ -645,7 +666,7 @@ public class InlineCodegen extends CallGenerator {
if (shouldPutValue(stackValue.type, stackValue)) { if (shouldPutValue(stackValue.type, stackValue)) {
stackValue.put(stackValue.type, codegen.v); 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); String targetFile = getSourceFilePath(targetDescriptor);
incrementalCache.registerInline(sourceFile, jvmSignature.toString(), targetFile); incrementalCache.registerInline(sourceFile, jvmSignature.toString(), targetFile);
} }
@Override
public void reorderArgumentsIfNeeded(@NotNull ArrayList<ArgumentAndIndex> actualArgsWithDeclIndex) {
}
} }
@@ -34,7 +34,6 @@ public class LocalVarRemapper {
private final int actualParamsSize; private final int actualParamsSize;
private final StackValue[] remapValues; private final StackValue[] remapValues;
private final int additionalShift; private final int additionalShift;
public LocalVarRemapper(Parameters params, int additionalShift) { public LocalVarRemapper(Parameters params, int additionalShift) {
@@ -42,20 +41,40 @@ public class LocalVarRemapper {
this.allParamsSize = params.totalSize(); this.allParamsSize = params.totalSize();
this.params = params; this.params = params;
int realSize = 0;
remapValues = new StackValue [params.totalSize()]; remapValues = new StackValue [params.totalSize()];
Integer [] declIndexesToActual = new Integer [params.totalSize()];
Integer [] actualDeclShifts = new Integer [params.totalSize()];
int index = 0; int index = 0;
for (ParameterInfo info : params) { for (ParameterInfo param : params) {
if (!info.isSkippedOrRemapped()) { if (param != ParameterInfo.STUB && param != CapturedParamInfo.STUB) {
remapValues[index] = StackValue.local(realSize, AsmTypes.OBJECT_TYPE); declIndexesToActual[param.declarationIndex] = index;
realSize += info.getType().getSize();
} else {
remapValues[index] = info.isRemapped() ? info.getRemapValue() : null;
} }
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; actualParamsSize = realSize;
} }
@@ -63,7 +82,7 @@ public class LocalVarRemapper {
int remappedIndex; int remappedIndex;
if (index < allParamsSize) { if (index < allParamsSize) {
ParameterInfo info = params.get(index); ParameterInfo info = params.getByByteCodeIndex(index);
StackValue remapped = remapValues[index]; StackValue remapped = remapValues[index];
if (info.isSkipped || remapped == null) { if (info.isSkipped || remapped == null) {
return new RemapInfo(info); return new RemapInfo(info);
@@ -559,7 +559,7 @@ public class MethodInliner {
private LambdaInfo getLambdaIfExists(int varIndex) { private LambdaInfo getLambdaIfExists(int varIndex) {
if (varIndex < parameters.totalSize()) { if (varIndex < parameters.totalSize()) {
return parameters.get(varIndex).getLambda(); return parameters.getByByteCodeIndex(varIndex).getLambda();
} }
return null; return null;
} }
@@ -24,31 +24,34 @@ import org.jetbrains.org.objectweb.asm.Type;
class ParameterInfo { 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 index;
protected final int declarationIndex;
private boolean isCaptured; private boolean isCaptured;
public final Type type; public final Type type;
//for skipped parameter: e.g. inlined lambda //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) //in case when parameter could be extracted from outer context (e.g. from local var)
private StackValue remapValue; private StackValue remapValue;
public LambdaInfo lambda; public LambdaInfo lambda;
ParameterInfo(Type type, boolean skipped, int index, int remapValue) { ParameterInfo(Type type, boolean skipped, int index, int remapValue, int declarationIndex) {
this(type, skipped, index, remapValue == -1 ? null : StackValue.local(remapValue, type)); 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.type = type;
this.isSkipped = skipped; this.isSkipped = skipped;
this.remapValue = remapValue; this.remapValue = remapValue;
this.index = index; this.index = index;
this.declarationIndex = declarationIndex;
} }
public boolean isSkippedOrRemapped() { public boolean isSkippedOrRemapped() {
@@ -82,19 +85,27 @@ class ParameterInfo {
return lambda; return lambda;
} }
public void setLambda(@Nullable LambdaInfo lambda) { public ParameterInfo setLambda(@Nullable LambdaInfo lambda) {
this.lambda = lambda; this.lambda = lambda;
return this;
} }
public void setRemapValue(StackValue remapValue) { public ParameterInfo setRemapValue(StackValue remapValue) {
this.remapValue = remapValue; this.remapValue = remapValue;
return this;
} }
public boolean isCaptured() { public boolean isCaptured() {
return isCaptured; return isCaptured;
} }
public ParameterInfo setSkipped(boolean skipped) {
isSkipped = skipped;
return this;
}
public void setCaptured(boolean isCaptured) { public void setCaptured(boolean isCaptured) {
this.isCaptured = isCaptured; this.isCaptured = isCaptured;
} }
} }
@@ -29,9 +29,32 @@ public class Parameters implements Iterable<ParameterInfo> {
private final List<ParameterInfo> real; private final List<ParameterInfo> real;
private final List<CapturedParamInfo> captured; private final List<CapturedParamInfo> captured;
private final Integer [] declIndexesToActual;
private final ParameterInfo [] actualDeclShifts;
public Parameters(List<ParameterInfo> real, List<CapturedParamInfo> captured) { public Parameters(List<ParameterInfo> real, List<CapturedParamInfo> captured) {
this.real = real; this.real = real;
this.captured = captured; 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<ParameterInfo> getReal() { public List<ParameterInfo> getReal() {
@@ -46,6 +69,17 @@ public class Parameters implements Iterable<ParameterInfo> {
return real.size() + captured.size(); 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) { public ParameterInfo get(int index) {
if (index < real.size()) { if (index < real.size()) {
return real.get(index); return real.get(index);
@@ -22,43 +22,54 @@ import org.jetbrains.org.objectweb.asm.Type
import java.util.ArrayList import java.util.ArrayList
import java.util.Collections import java.util.Collections
class ParametersBuilder { class ParametersBuilder private constructor(){
private val params = ArrayList<ParameterInfo>() private val valueAndHiddenParams = arrayListOf<ParameterInfo>()
private val capturedParams = ArrayList<CapturedParamInfo>() private val capturedParams = arrayListOf<CapturedParamInfo>()
private var valueParamStart = 0
var nextValueParameterIndex = 0 var nextValueParameterIndex = 0
private set private set
private var nextCaptured = 0 private var nextCaptured = 0
fun addThis(type: Type, skipped: Boolean): ParameterInfo { 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) addParameter(info)
return info return info
} }
fun addNextParameter(type: Type, skipped: Boolean, remapValue: StackValue?): ParameterInfo { 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( fun addCapturedParam(
original: CapturedParamInfo, original: CapturedParamInfo,
newFieldName: String): 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()) info.setLambda(original.getLambda())
return addCapturedParameter(info) return addCapturedParameter(info)
} }
private fun nextCapturedIndex(): Int {
return nextCaptured
}
fun addCapturedParam( fun addCapturedParam(
desc: CapturedParamDesc, desc: CapturedParamDesc,
newFieldName: String): CapturedParamInfo { newFieldName: String): CapturedParamInfo {
val info = CapturedParamInfo(desc, newFieldName, false, nextCaptured, null) val info = CapturedParamInfo(desc, newFieldName, false, nextCapturedIndex(), null)
return addCapturedParameter(info) return addCapturedParameter(info)
} }
fun addCapturedParamCopy( fun addCapturedParamCopy(
copyFrom: CapturedParamInfo): CapturedParamInfo { copyFrom: CapturedParamInfo): CapturedParamInfo {
val info = copyFrom.newIndex(nextCaptured) val info = copyFrom.newIndex(nextCapturedIndex())
return addCapturedParameter(info) return addCapturedParameter(info)
} }
@@ -68,7 +79,7 @@ class ParametersBuilder {
type: Type, type: Type,
skipped: Boolean, skipped: Boolean,
original: ParameterInfo?): CapturedParamInfo { 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) original.getIndex() else -1)
if (original != null) { if (original != null) {
info.setLambda(original.getLambda()) info.setLambda(original.getLambda())
@@ -77,7 +88,7 @@ class ParametersBuilder {
} }
private fun addParameter(info: ParameterInfo): ParameterInfo { private fun addParameter(info: ParameterInfo): ParameterInfo {
params.add(info) valueAndHiddenParams.add(info)
nextValueParameterIndex += info.getType().size nextValueParameterIndex += info.getType().size
return info return info
} }
@@ -89,7 +100,11 @@ class ParametersBuilder {
} }
fun listNotCaptured(): List<ParameterInfo> { fun listNotCaptured(): List<ParameterInfo> {
return Collections.unmodifiableList(params) return Collections.unmodifiableList(valueAndHiddenParams)
}
fun markValueParametesStart(){
this.valueParamStart = valueAndHiddenParams.size()
} }
fun listCaptured(): List<CapturedParamInfo> { fun listCaptured(): List<CapturedParamInfo> {
@@ -97,9 +112,7 @@ class ParametersBuilder {
} }
fun listAllParams(): List<ParameterInfo> { fun listAllParams(): List<ParameterInfo> {
val list = ArrayList(params) return valueAndHiddenParams + capturedParams
list.addAll(capturedParams)
return list
} }
private fun buildWithStubs(): List<ParameterInfo> { private fun buildWithStubs(): List<ParameterInfo> {
@@ -114,16 +127,24 @@ class ParametersBuilder {
return Parameters(buildWithStubs(), buildCapturedWithStubs()) return Parameters(buildWithStubs(), buildCapturedWithStubs())
} }
// public fun getValueParameter(index: Int): ParameterInfo {
// return valueAndHiddenParams[index + valueParamStart]
// }
companion object { companion object {
@JvmStatic fun newBuilder(): ParametersBuilder { @JvmStatic
fun newBuilder(): ParametersBuilder {
return 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() val builder = newBuilder()
//skipped this for inlined lambda cause it will be removed if (addThis) {
builder.addThis(objectType, inlineLambda != null).setLambda(inlineLambda) //skipped this for inlined lambda cause it will be removed
builder.addThis(objectType, inlineLambda != null).setLambda(inlineLambda)
}
val types = Type.getArgumentTypes(descriptor) val types = Type.getArgumentTypes(descriptor)
for (type in types) { for (type in types) {
@@ -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"
}
@@ -0,0 +1,5 @@
package test
inline fun test(a: String, b: String, c: () -> String): String {
return a + b + c();
}
@@ -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"
}
@@ -0,0 +1,5 @@
package test
inline fun test(a: String, b: String, c: () -> String): String {
return a + b + c();
}
@@ -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") @TestMetadata("compiler/testData/codegen/boxInline/builders")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -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") @TestMetadata("compiler/testData/codegen/boxInline/builders")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)