Add default lambda inlining prototype
This commit is contained in:
@@ -28,6 +28,7 @@ enum class ValueKind {
|
||||
DEFAULT_MASK,
|
||||
METHOD_HANDLE_IN_DEFAULT,
|
||||
CAPTURED,
|
||||
DEFAULT_LAMBDA_CAPTURED_PARAMETER
|
||||
}
|
||||
|
||||
abstract class CallGenerator {
|
||||
|
||||
@@ -417,6 +417,11 @@ public class InlineCodegen extends CallGenerator {
|
||||
node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex,
|
||||
DefaultMethodUtilKt.extractDefaultLambdaOffsetAndDescriptor(jvmSignature, functionDescriptor)
|
||||
);
|
||||
for (DefaultLambda lambda : defaultLambdas) {
|
||||
invocationParamBuilder.buildParameters().getParameterByDeclarationSlot(lambda.getOffset()).setLambda(lambda);
|
||||
LambdaInfo prev = expressionMap.put(lambda.getOffset(), lambda);
|
||||
assert prev == null : "Lambda with offset " + lambda.getOffset() + " already exists: " + prev;
|
||||
}
|
||||
}
|
||||
ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node);
|
||||
generateClosuresBodies();
|
||||
@@ -668,7 +673,11 @@ public class InlineCodegen extends CallGenerator {
|
||||
info = invocationParamBuilder.addNextValueParameter(type, false, remappedValue, parameterIndex);
|
||||
}
|
||||
|
||||
recordParameterValueInLocalVal(false, isDefaultParameter, info);
|
||||
recordParameterValueInLocalVal(
|
||||
false,
|
||||
isDefaultParameter || kind == ValueKind.DEFAULT_LAMBDA_CAPTURED_PARAMETER,
|
||||
info
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -826,12 +835,34 @@ public class InlineCodegen extends CallGenerator {
|
||||
if (next instanceof ExpressionLambda) {
|
||||
codegen.pushClosureOnStack(((ExpressionLambda) next).getClassDescriptor(), true, this, functionReferenceReceiver);
|
||||
}
|
||||
else if (next instanceof DefaultLambda) {
|
||||
rememberCapturedForDefaultLambda((DefaultLambda) next);
|
||||
}
|
||||
else {
|
||||
//TODO
|
||||
throw new RuntimeException("Unknown lambda: " + next);
|
||||
}
|
||||
activeLambda = null;
|
||||
}
|
||||
|
||||
private void rememberCapturedForDefaultLambda(@NotNull DefaultLambda defaultLambda) {
|
||||
List<CapturedParamDesc> vars = defaultLambda.getCapturedVars();
|
||||
int paramIndex = 0;
|
||||
for (CapturedParamDesc captured : vars) {
|
||||
putArgumentOrCapturedToLocalVal(
|
||||
captured.getType(),
|
||||
//HACK: actually parameter would be placed on stack in default function
|
||||
// also see ValueKind.DEFAULT_LAMBDA_CAPTURED_PARAMETER check
|
||||
StackValue.onStack(captured.getType()),
|
||||
paramIndex,
|
||||
paramIndex,
|
||||
ValueKind.DEFAULT_LAMBDA_CAPTURED_PARAMETER
|
||||
);
|
||||
|
||||
paramIndex++;
|
||||
defaultLambda.getParameterOffsetsInDefault().add(invocationParamBuilder.getNextParameterOffset());
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static CodegenContext getContext(
|
||||
@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state, @Nullable KtFile sourceFile
|
||||
|
||||
@@ -84,6 +84,8 @@ class DefaultLambda(
|
||||
val offset: Int
|
||||
) : LambdaInfo(parameterDescriptor.isCrossinline, false) {
|
||||
|
||||
val parameterOffsetsInDefault: MutableList<Int> = arrayListOf()
|
||||
|
||||
override lateinit var invokeMethod: Method
|
||||
private set
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ public class LocalVarRemapper {
|
||||
}
|
||||
else {
|
||||
//captured params are not used directly in this inlined method, they are used in closure
|
||||
//except captured ones for default lambdas, they are generated in default body
|
||||
remappedIndex = actualParamsSize - params.getArgsSizeOnStack() + index;
|
||||
}
|
||||
|
||||
|
||||
@@ -332,6 +332,22 @@ class MethodInliner(
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitMethodInsn(opcode: Int, owner: String, name: String, desc: String, itf: Boolean) {
|
||||
if (InlineCodegenUtil.DEFAULT_LAMBDA_FAKE_CALL == owner) {
|
||||
val index = name.substringAfter(InlineCodegenUtil.DEFAULT_LAMBDA_FAKE_CALL).toInt()
|
||||
val lambda = getLambdaIfExists(index) as DefaultLambda
|
||||
lambda.parameterOffsetsInDefault.zip(lambda.capturedVars).asReversed().forEach {
|
||||
(_, captured) ->
|
||||
super.visitFieldInsn(
|
||||
Opcodes.PUTSTATIC, captured.containingLambdaName, "$$$" + captured.fieldName, captured.type.descriptor
|
||||
)
|
||||
}
|
||||
}
|
||||
else {
|
||||
super.visitMethodInsn(opcode, owner, name, desc, itf)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitLocalVariable(
|
||||
name: String, desc: String, signature: String?, start: Label, end: Label, index: Int
|
||||
) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.codegen.StackValue;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode;
|
||||
|
||||
@@ -62,7 +63,12 @@ public class RemapVisitor extends MethodBodyVisitor {
|
||||
FieldInsnNode fin = new FieldInsnNode(opcode, owner, name, desc);
|
||||
StackValue inline = nodeRemapper.getFieldForInline(fin, null);
|
||||
assert inline != null : "Captured field should have not null stackValue " + fin;
|
||||
inline.put(inline.type, this);
|
||||
if (Opcodes.PUTSTATIC == opcode) {
|
||||
inline.store(StackValue.onStack(inline.type), this);
|
||||
}
|
||||
else {
|
||||
inline.put(inline.type, this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
super.visitFieldInsn(opcode, owner, name, desc);
|
||||
|
||||
Reference in New Issue
Block a user