Convert LambdaInfo.java to Kotlin

This commit is contained in:
Mikhael Bogdanov
2017-05-04 11:01:00 +02:00
parent f8f4fc5de1
commit 9c51392aff
3 changed files with 107 additions and 169 deletions
@@ -575,7 +575,8 @@ public class InlineCodegen extends CallGenerator {
Type asmType = state.getTypeMapper().mapClass(lambdaInfo.getClassDescriptor()); Type asmType = state.getTypeMapper().mapClass(lambdaInfo.getClassDescriptor());
PropertyReferenceInfo info = lambdaInfo.getPropertyReferenceInfo(); PropertyReferenceInfo info = lambdaInfo.getPropertyReferenceInfo();
strategy = new PropertyReferenceCodegen.PropertyReferenceGenerationStrategy( strategy = new PropertyReferenceCodegen.PropertyReferenceGenerationStrategy(
true, info.getGetFunction(), info.getTarget(), asmType, receiverType, lambdaInfo.expression, state, true); true, info.getGetFunction(), info.getTarget(), asmType, receiverType,
lambdaInfo.getFunctionWithBodyOrCallableReference(), state, true);
} }
else { else {
strategy = new FunctionReferenceGenerationStrategy( strategy = new FunctionReferenceGenerationStrategy(
@@ -14,191 +14,128 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.codegen.inline; package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.annotations.NotNull; import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.codegen.AsmUtil; import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.PropertyReferenceCodegen; import org.jetbrains.kotlin.codegen.PropertyReferenceCodegen
import org.jetbrains.kotlin.codegen.StackValue; import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure; import org.jetbrains.kotlin.codegen.binding.CalculatedClosure
import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor; import org.jetbrains.kotlin.codegen.binding.CodegenBinding.*
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.codegen.binding.MutableClosure
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.psi.KtLambdaExpression; import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.jvm.AsmTypes; import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.commons.Method; import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode; import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
import java.util.*
import java.util.ArrayList; class LambdaInfo(
import java.util.Arrays; expression: KtExpression,
import java.util.List; private val typeMapper: KotlinTypeMapper,
import java.util.Set; @JvmField val isCrossInline: Boolean,
val isBoundCallableReference: Boolean
) : LabelOwner {
val functionWithBodyOrCallableReference: KtExpression = (expression as? KtLambdaExpression)?.functionLiteral ?: expression
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*; val labels: Set<String>
private lateinit var closure: CalculatedClosure
val functionDescriptor: FunctionDescriptor
val classDescriptor: ClassDescriptor
val lambdaClassType: Type
public class LambdaInfo implements LabelOwner { var node: SMAPAndMethodNode? = null
public final KtExpression expression; val propertyReferenceInfo: PropertyReferenceInfo?
private final KotlinTypeMapper typeMapper;
public final Set<String> labels;
private final CalculatedClosure closure;
public final boolean isCrossInline;
private final FunctionDescriptor functionDescriptor;
private final ClassDescriptor classDescriptor;
private final Type closureClassType;
private SMAPAndMethodNode node; init {
private List<CapturedParamDesc> capturedVars; val bindingContext = typeMapper.bindingContext
private final boolean isBoundCallableReference; val function = bindingContext.get<PsiElement, SimpleFunctionDescriptor>(BindingContext.FUNCTION, this.functionWithBodyOrCallableReference)
private final PropertyReferenceInfo propertyReferenceInfo; if (function == null && expression is KtCallableReferenceExpression) {
val variableDescriptor = bindingContext.get<PsiElement, VariableDescriptor>(BindingContext.VARIABLE, this.functionWithBodyOrCallableReference)
public LambdaInfo(@NotNull KtExpression expression, @NotNull KotlinTypeMapper typeMapper, boolean isCrossInline, boolean isBoundCallableReference) { assert(variableDescriptor is VariableDescriptorWithAccessors) { "Reference expression not resolved to variable descriptor with accessors: " + expression.getText() }
this.isCrossInline = isCrossInline; classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor!!)
this.expression = expression instanceof KtLambdaExpression ? lambdaClassType = typeMapper.mapClass(classDescriptor)
((KtLambdaExpression) expression).getFunctionLiteral() : expression; val getFunction = PropertyReferenceCodegen.findGetFunction(variableDescriptor)
functionDescriptor = PropertyReferenceCodegen.createFakeOpenDescriptor(getFunction, classDescriptor)
this.typeMapper = typeMapper; val resolvedCall = expression.callableReference.getResolvedCallWithAssert(bindingContext)
this.isBoundCallableReference = isBoundCallableReference; propertyReferenceInfo = PropertyReferenceInfo(
BindingContext bindingContext = typeMapper.getBindingContext(); resolvedCall.resultingDescriptor as VariableDescriptor, getFunction
FunctionDescriptor function = bindingContext.get(BindingContext.FUNCTION, this.expression); )
if (function == null && expression instanceof KtCallableReferenceExpression) {
VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, this.expression);
assert variableDescriptor instanceof VariableDescriptorWithAccessors :
"Reference expression not resolved to variable descriptor with accessors: " + expression.getText();
classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor);
closureClassType = typeMapper.mapClass(classDescriptor);
SimpleFunctionDescriptor getFunction = PropertyReferenceCodegen.findGetFunction(variableDescriptor);
functionDescriptor = PropertyReferenceCodegen.createFakeOpenDescriptor(getFunction, classDescriptor);
ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(((KtCallableReferenceExpression) expression).getCallableReference(), bindingContext);
propertyReferenceInfo = new PropertyReferenceInfo(
(VariableDescriptor) resolvedCall.getResultingDescriptor(), getFunction
);
} }
else { else {
propertyReferenceInfo = null; propertyReferenceInfo = null
functionDescriptor = function; assert(function != null) { "Function is not resolved to descriptor: " + expression.text }
assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText(); functionDescriptor = function!!
classDescriptor = anonymousClassForCallable(bindingContext, functionDescriptor); classDescriptor = anonymousClassForCallable(bindingContext, functionDescriptor)
closureClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor); lambdaClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor)
} }
bindingContext.get<ClassDescriptor, MutableClosure>(CLOSURE, classDescriptor).let {
closure = bindingContext.get(CLOSURE, classDescriptor); assert(it != null) { "Closure for lambda should be not null " + expression.text }
assert closure != null : "Closure for lambda should be not null " + expression.getText(); closure = it!!
labels = InlineCodegen.getDeclarationLabels(expression, functionDescriptor);
}
@NotNull
public SMAPAndMethodNode getNode() {
return node;
}
public void setNode(@NotNull SMAPAndMethodNode node) {
this.node = node;
}
@NotNull
public FunctionDescriptor getFunctionDescriptor() {
return functionDescriptor;
}
@NotNull
public KtExpression getFunctionWithBodyOrCallableReference() {
return expression;
}
@NotNull
public ClassDescriptor getClassDescriptor() {
return classDescriptor;
}
@NotNull
public Type getLambdaClassType() {
return closureClassType;
}
@NotNull
public List<CapturedParamDesc> getCapturedVars() {
//lazy initialization cause it would be calculated after object creation
if (capturedVars == null) {
capturedVars = new ArrayList<>();
if (closure.getCaptureThis() != null) {
Type type = typeMapper.mapType(closure.getCaptureThis());
EnclosedValueDescriptor descriptor =
new EnclosedValueDescriptor(
AsmUtil.CAPTURED_THIS_FIELD,
/* descriptor = */ null,
StackValue.field(type, closureClassType, AsmUtil.CAPTURED_THIS_FIELD, false, StackValue.LOCAL_0),
type
);
capturedVars.add(getCapturedParamInfo(descriptor));
}
if (closure.getCaptureReceiverType() != null) {
Type type = typeMapper.mapType(closure.getCaptureReceiverType());
EnclosedValueDescriptor descriptor =
new EnclosedValueDescriptor(
AsmUtil.CAPTURED_RECEIVER_FIELD,
/* descriptor = */ null,
StackValue.field(type, closureClassType, AsmUtil.CAPTURED_RECEIVER_FIELD, false, StackValue.LOCAL_0),
type
);
capturedVars.add(getCapturedParamInfo(descriptor));
}
for (EnclosedValueDescriptor descriptor : closure.getCaptureVariables().values()) {
capturedVars.add(getCapturedParamInfo(descriptor));
}
}
return capturedVars;
}
@NotNull
private CapturedParamDesc getCapturedParamInfo(@NotNull EnclosedValueDescriptor descriptor) {
return new CapturedParamDesc(closureClassType, descriptor.getFieldName(), descriptor.getType());
}
@NotNull
public List<Type> getInvokeParamsWithoutCaptured() {
return Arrays.asList(typeMapper.mapAsmMethod(functionDescriptor).getArgumentTypes());
}
@NotNull
public Parameters addAllParameters(@NotNull FieldRemapper remapper) {
Method asmMethod = typeMapper.mapAsmMethod(getFunctionDescriptor());
ParametersBuilder builder = ParametersBuilder.initializeBuilderFrom(AsmTypes.OBJECT_TYPE, asmMethod.getDescriptor(), this);
for (CapturedParamDesc info : getCapturedVars()) {
CapturedParamInfo field = remapper.findField(new FieldInsnNode(0, info.getContainingLambdaName(), info.getFieldName(), ""));
assert field != null : "Captured field not found: " + info.getContainingLambdaName() + "." + info.getFieldName();
builder.addCapturedParam(field, info.getFieldName());
} }
return builder.buildParameters(); labels = InlineCodegen.getDeclarationLabels(expression, functionDescriptor)
} }
@Override val capturedVars: List<CapturedParamDesc> by lazy {
public boolean isMyLabel(@NotNull String name) { arrayListOf<CapturedParamDesc>().apply {
return labels.contains(name); if (closure.captureThis != null) {
val type = typeMapper.mapType(closure.captureThis!!)
val descriptor = EnclosedValueDescriptor(
AsmUtil.CAPTURED_THIS_FIELD, null,
StackValue.field(type, lambdaClassType, AsmUtil.CAPTURED_THIS_FIELD, false, StackValue.LOCAL_0),
type
)
add(getCapturedParamInfo(descriptor))
}
if (closure.captureReceiverType != null) {
val type = typeMapper.mapType(closure.captureReceiverType!!)
val descriptor = EnclosedValueDescriptor(
AsmUtil.CAPTURED_RECEIVER_FIELD, null,
StackValue.field(type, lambdaClassType, AsmUtil.CAPTURED_RECEIVER_FIELD, false, StackValue.LOCAL_0),
type
)
add(getCapturedParamInfo(descriptor))
}
closure.captureVariables.values.forEach {
descriptor -> add(getCapturedParamInfo(descriptor))
}
}
} }
public boolean isBoundCallableReference() { private fun getCapturedParamInfo(descriptor: EnclosedValueDescriptor): CapturedParamDesc {
return isBoundCallableReference; return CapturedParamDesc(lambdaClassType, descriptor.fieldName, descriptor.type)
} }
public boolean isPropertyReference() { val invokeParamsWithoutCaptured: List<Type>
return propertyReferenceInfo != null; get() = Arrays.asList(*typeMapper.mapAsmMethod(functionDescriptor).argumentTypes)
fun addAllParameters(remapper: FieldRemapper): Parameters {
val asmMethod = typeMapper.mapAsmMethod(functionDescriptor)
val builder = ParametersBuilder.initializeBuilderFrom(AsmTypes.OBJECT_TYPE, asmMethod.descriptor, this)
for (info in capturedVars) {
val field = remapper.findField(FieldInsnNode(0, info.containingLambdaName, info.fieldName, "")) ?: error("Captured field not found: " + info.containingLambdaName + "." + info.fieldName)
builder.addCapturedParam(field, info.fieldName)
}
return builder.buildParameters()
} }
public PropertyReferenceInfo getPropertyReferenceInfo() { override fun isMyLabel(name: String): Boolean {
return propertyReferenceInfo; return labels.contains(name)
} }
val isPropertyReference: Boolean
get() = propertyReferenceInfo != null
} }
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import java.util.* import java.util.*
internal class Parameters(val parameters: List<ParameterInfo>) : Iterable<ParameterInfo> { class Parameters(val parameters: List<ParameterInfo>) : Iterable<ParameterInfo> {
private val actualDeclShifts: Array<ParameterInfo?> private val actualDeclShifts: Array<ParameterInfo?>
private val paramToDeclByteCodeIndex: HashMap<ParameterInfo, Int> = hashMapOf() private val paramToDeclByteCodeIndex: HashMap<ParameterInfo, Int> = hashMapOf()