Proper param propagation in inline
This commit is contained in:
@@ -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<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.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<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();
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reorderArgumentsIfNeeded(@NotNull ArrayList<ArgumentAndIndex> args) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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<ParameterInfo> 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<ArgumentAndIndex> actualArgsWithDeclIndex) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,9 +29,32 @@ public class Parameters implements Iterable<ParameterInfo> {
|
||||
private final List<ParameterInfo> real;
|
||||
private final List<CapturedParamInfo> captured;
|
||||
|
||||
private final Integer [] declIndexesToActual;
|
||||
private final ParameterInfo [] actualDeclShifts;
|
||||
|
||||
public Parameters(List<ParameterInfo> real, List<CapturedParamInfo> 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<ParameterInfo> getReal() {
|
||||
@@ -46,6 +69,17 @@ public class Parameters implements Iterable<ParameterInfo> {
|
||||
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);
|
||||
|
||||
@@ -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<ParameterInfo>()
|
||||
private val capturedParams = ArrayList<CapturedParamInfo>()
|
||||
private val valueAndHiddenParams = arrayListOf<ParameterInfo>()
|
||||
private val capturedParams = arrayListOf<CapturedParamInfo>()
|
||||
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<ParameterInfo> {
|
||||
return Collections.unmodifiableList(params)
|
||||
return Collections.unmodifiableList(valueAndHiddenParams)
|
||||
}
|
||||
|
||||
fun markValueParametesStart(){
|
||||
this.valueParamStart = valueAndHiddenParams.size()
|
||||
}
|
||||
|
||||
fun listCaptured(): List<CapturedParamInfo> {
|
||||
@@ -97,9 +112,7 @@ class ParametersBuilder {
|
||||
}
|
||||
|
||||
fun listAllParams(): List<ParameterInfo> {
|
||||
val list = ArrayList(params)
|
||||
list.addAll(capturedParams)
|
||||
return list
|
||||
return valueAndHiddenParams + capturedParams
|
||||
}
|
||||
|
||||
private fun buildWithStubs(): List<ParameterInfo> {
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
+21
@@ -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)
|
||||
|
||||
+21
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user