Convert LambdaInfo.java to Kotlin
This commit is contained in:
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user