All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.codegen.context.LocalLookup Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

package org.jetbrains.kotlin.codegen.context;

import kotlin.text.StringsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.codegen.AsmUtil;
import org.jetbrains.kotlin.codegen.ExpressionCodegen;
import org.jetbrains.kotlin.codegen.JvmCodegenUtil;
import org.jetbrains.kotlin.codegen.StackValue;
import org.jetbrains.kotlin.codegen.binding.MutableClosure;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.org.objectweb.asm.Type;

import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isLocalFunction;

public interface LocalLookup {
    boolean isLocal(DeclarationDescriptor descriptor);

    enum LocalLookupCase {
        VAR {
            @Override
            public boolean isCase(DeclarationDescriptor d) {
                return d instanceof VariableDescriptor && !(d instanceof PropertyDescriptor);
            }

            @Override
            public StackValue.StackValueWithSimpleReceiver innerValue(
                    DeclarationDescriptor d,
                    LocalLookup localLookup,
                    GenerationState state,
                    MutableClosure closure,
                    Type classType
            ) {
                VariableDescriptor vd = (VariableDescriptor) d;

                boolean idx = localLookup != null && localLookup.isLocal(vd);
                if (!idx) return null;

                KotlinType delegateType =
                        vd instanceof VariableDescriptorWithAccessors
                        ? JvmCodegenUtil.getPropertyDelegateType((VariableDescriptorWithAccessors) vd, state.getBindingContext())
                        : null;
                Type sharedVarType = state.getTypeMapper().getSharedVarType(vd);
                KotlinType localKotlinType = delegateType != null ? delegateType : vd.getType();
                Type localType = state.getTypeMapper().mapType(localKotlinType);
                Type type = sharedVarType != null ? sharedVarType : localType;
                KotlinType kotlinType = sharedVarType != null ? null : localKotlinType;

                String fieldName = AsmUtil.getCapturedFieldName(vd.getName().asString());
                StackValue.Local thiz = StackValue.LOCAL_0;

                StackValue.StackValueWithSimpleReceiver innerValue;
                EnclosedValueDescriptor enclosedValueDescriptor;
                if (sharedVarType != null) {
                    StackValue.Field wrapperValue = StackValue.receiverWithRefWrapper(localType, classType, fieldName, thiz, vd);
                    innerValue = StackValue.fieldForSharedVar(localType, classType, fieldName, wrapperValue, vd);
                    enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, wrapperValue, type, kotlinType);
                }
                else {
                    innerValue = StackValue.field(type, kotlinType, classType, fieldName, false, thiz, vd);
                    enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, type, kotlinType);
                }

                closure.captureVariable(enclosedValueDescriptor);

                return innerValue;
            }
        },

        LOCAL_NAMED_FUNCTION {
            @Override
            public boolean isCase(DeclarationDescriptor d) {
                return isLocalFunction(d);
            }

            @Override
            public StackValue.StackValueWithSimpleReceiver innerValue(
                    DeclarationDescriptor d,
                    LocalLookup localLookup,
                    GenerationState state,
                    MutableClosure closure,
                    Type classType
            ) {
                FunctionDescriptor vd = (FunctionDescriptor) d;

                boolean idx = localLookup != null && localLookup.isLocal(vd);
                if (!idx) return null;

                BindingContext bindingContext = state.getBindingContext();
                Type localType = asmTypeForAnonymousClass(bindingContext, vd);

                ClassDescriptor callableClass = bindingContext.get(CLASS_FOR_CALLABLE, vd);
                assert callableClass != null : "No CLASS_FOR_CALLABLE:" + vd;

                MutableClosure localFunClosure = bindingContext.get(CLOSURE, callableClass);
                if (localFunClosure != null && JvmCodegenUtil.isConst(localFunClosure)) {
                    // This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance
                    // (instead of passing this instance to the constructor and storing as a field)
                    return StackValue.field(localType, null, localType, JvmAbi.INSTANCE_FIELD, true, StackValue.LOCAL_0, vd);
                }

                String internalName = localType.getInternalName();
                String simpleName = StringsKt.substringAfterLast(internalName, "/", internalName);
                int localClassIndexStart = simpleName.lastIndexOf('$');
                String localFunSuffix = localClassIndexStart >= 0 ? simpleName.substring(localClassIndexStart) : "";

                String fieldName = AsmUtil.getCapturedFieldName(vd.getName().asString()) + localFunSuffix;
                StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(
                        localType, null, classType, fieldName, false, StackValue.LOCAL_0, vd
                );

                closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType, null));

                return innerValue;
            }
        },

        RECEIVER {
            @Override
            public boolean isCase(DeclarationDescriptor d) {
                return d instanceof ReceiverParameterDescriptor;
            }

            @Override
            public StackValue.StackValueWithSimpleReceiver innerValue(
                    DeclarationDescriptor d,
                    LocalLookup enclosingLocalLookup,
                    GenerationState state,
                    MutableClosure closure,
                    Type classType
            ) {
                CallableDescriptor enclosingCallableWithReceiver = closure.getEnclosingCallableDescriptorWithReceiver();
                ReceiverParameterDescriptor enclosingReceiverDescriptor =
                        enclosingCallableWithReceiver != null ? enclosingCallableWithReceiver.getExtensionReceiverParameter() : null;

                if (enclosingReceiverDescriptor != d) {
                    return null;
                }

                assert(enclosingReceiverDescriptor != null);

                KotlinType receiverType = enclosingReceiverDescriptor.getType();
                Type type = state.getTypeMapper().mapType(receiverType);
                String fieldName = closure.getCapturedReceiverFieldName(state.getBindingContext(), state.getLanguageVersionSettings());
                StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(
                        type, receiverType, classType, fieldName, false, StackValue.LOCAL_0, d
                );
                closure.setNeedsCaptureReceiverFromOuterContext();

                return innerValue;
            }

            @NotNull
            @Override
            public StackValue outerValue(@NotNull EnclosedValueDescriptor d, @NotNull ExpressionCodegen codegen) {
                CallableDescriptor descriptor = (CallableDescriptor) d.getDescriptor();
                return StackValue.local(descriptor.getDispatchReceiverParameter() != null ? 1 : 0, d.getType());
            }
        };

        public abstract boolean isCase(DeclarationDescriptor d);

        public abstract StackValue.StackValueWithSimpleReceiver innerValue(
                DeclarationDescriptor d,
                LocalLookup localLookup,
                GenerationState state,
                MutableClosure closure,
                Type classType
        );

        @NotNull
        public StackValue outerValue(@NotNull EnclosedValueDescriptor d, @NotNull ExpressionCodegen codegen) {
            DeclarationDescriptor declarationDescriptor = d.getDescriptor();
            int idx = codegen.lookupLocalIndex(declarationDescriptor);
            if (idx >= 0) {
                return StackValue.local(idx, d.getType());
            }
            else {
                assert declarationDescriptor != null : "No declaration descriptor for " + d;
                StackValue capturedValue = codegen.findCapturedValue(declarationDescriptor);
                assert capturedValue != null : "Unresolved captured value for " + d;
                return capturedValue;
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy