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());
PropertyReferenceInfo info = lambdaInfo.getPropertyReferenceInfo();
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 {
strategy = new FunctionReferenceGenerationStrategy(
@@ -14,191 +14,128 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.inline;
package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.codegen.AsmUtil;
import org.jetbrains.kotlin.codegen.PropertyReferenceCodegen;
import org.jetbrains.kotlin.codegen.StackValue;
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.KtLambdaExpression;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.commons.Method;
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode;
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.PropertyReferenceCodegen
import org.jetbrains.kotlin.codegen.StackValue
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.binding.MutableClosure
import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
import java.util.*
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
class LambdaInfo(
expression: KtExpression,
private val typeMapper: KotlinTypeMapper,
@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 {
public final KtExpression expression;
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;
var node: SMAPAndMethodNode? = null
val propertyReferenceInfo: PropertyReferenceInfo?
private SMAPAndMethodNode node;
private List<CapturedParamDesc> capturedVars;
private final boolean isBoundCallableReference;
private final PropertyReferenceInfo propertyReferenceInfo;
public LambdaInfo(@NotNull KtExpression expression, @NotNull KotlinTypeMapper typeMapper, boolean isCrossInline, boolean isBoundCallableReference) {
this.isCrossInline = isCrossInline;
this.expression = expression instanceof KtLambdaExpression ?
((KtLambdaExpression) expression).getFunctionLiteral() : expression;
this.typeMapper = typeMapper;
this.isBoundCallableReference = isBoundCallableReference;
BindingContext bindingContext = typeMapper.getBindingContext();
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
);
init {
val bindingContext = typeMapper.bindingContext
val function = bindingContext.get<PsiElement, SimpleFunctionDescriptor>(BindingContext.FUNCTION, this.functionWithBodyOrCallableReference)
if (function == null && expression is KtCallableReferenceExpression) {
val variableDescriptor = bindingContext.get<PsiElement, VariableDescriptor>(BindingContext.VARIABLE, this.functionWithBodyOrCallableReference)
assert(variableDescriptor is VariableDescriptorWithAccessors) { "Reference expression not resolved to variable descriptor with accessors: " + expression.getText() }
classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor!!)
lambdaClassType = typeMapper.mapClass(classDescriptor)
val getFunction = PropertyReferenceCodegen.findGetFunction(variableDescriptor)
functionDescriptor = PropertyReferenceCodegen.createFakeOpenDescriptor(getFunction, classDescriptor)
val resolvedCall = expression.callableReference.getResolvedCallWithAssert(bindingContext)
propertyReferenceInfo = PropertyReferenceInfo(
resolvedCall.resultingDescriptor as VariableDescriptor, getFunction
)
}
else {
propertyReferenceInfo = null;
functionDescriptor = function;
assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText();
classDescriptor = anonymousClassForCallable(bindingContext, functionDescriptor);
closureClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor);
propertyReferenceInfo = null
assert(function != null) { "Function is not resolved to descriptor: " + expression.text }
functionDescriptor = function!!
classDescriptor = anonymousClassForCallable(bindingContext, functionDescriptor)
lambdaClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor)
}
closure = bindingContext.get(CLOSURE, classDescriptor);
assert closure != null : "Closure for lambda should be not null " + expression.getText();
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());
bindingContext.get<ClassDescriptor, MutableClosure>(CLOSURE, classDescriptor).let {
assert(it != null) { "Closure for lambda should be not null " + expression.text }
closure = it!!
}
return builder.buildParameters();
labels = InlineCodegen.getDeclarationLabels(expression, functionDescriptor)
}
@Override
public boolean isMyLabel(@NotNull String name) {
return labels.contains(name);
val capturedVars: List<CapturedParamDesc> by lazy {
arrayListOf<CapturedParamDesc>().apply {
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() {
return isBoundCallableReference;
private fun getCapturedParamInfo(descriptor: EnclosedValueDescriptor): CapturedParamDesc {
return CapturedParamDesc(lambdaClassType, descriptor.fieldName, descriptor.type)
}
public boolean isPropertyReference() {
return propertyReferenceInfo != null;
val invokeParamsWithoutCaptured: List<Type>
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() {
return propertyReferenceInfo;
override fun isMyLabel(name: String): Boolean {
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 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 paramToDeclByteCodeIndex: HashMap<ParameterInfo, Int> = hashMapOf()