001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.codegen.context;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.kotlin.codegen.AsmUtil;
022    import org.jetbrains.kotlin.codegen.JvmCodegenUtil;
023    import org.jetbrains.kotlin.codegen.OwnerKind;
024    import org.jetbrains.kotlin.codegen.StackValue;
025    import org.jetbrains.kotlin.codegen.binding.MutableClosure;
026    import org.jetbrains.kotlin.codegen.state.GenerationState;
027    import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
028    import org.jetbrains.kotlin.descriptors.*;
029    import org.jetbrains.org.objectweb.asm.Label;
030    import org.jetbrains.org.objectweb.asm.Type;
031    
032    public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
033        private final boolean isInliningLambda;
034        private Label methodStartLabel;
035        private Label methodEndLabel;
036    
037        // Note: in case of code inside property accessors, functionDescriptor will be that accessor,
038        // but CodegenContext#contextDescriptor will be the corresponding property
039        private final FunctionDescriptor functionDescriptor;
040    
041        protected MethodContext(
042                @NotNull FunctionDescriptor functionDescriptor,
043                @NotNull OwnerKind contextKind,
044                @NotNull CodegenContext parentContext,
045                @Nullable MutableClosure closure,
046                boolean isInliningLambda
047        ) {
048            super(JvmCodegenUtil.getDirectMember(functionDescriptor), contextKind, parentContext, closure,
049                  parentContext.hasThisDescriptor() ? parentContext.getThisDescriptor() : null, null);
050            this.isInliningLambda = isInliningLambda;
051            this.functionDescriptor = functionDescriptor;
052        }
053    
054        @NotNull
055        @Override
056        public CodegenContext getParentContext() {
057            //noinspection ConstantConditions
058            return super.getParentContext();
059        }
060    
061        public StackValue getReceiverExpression(JetTypeMapper typeMapper) {
062            assert getCallableDescriptorWithReceiver() != null;
063            @SuppressWarnings("ConstantConditions")
064            Type asmType = typeMapper.mapType(getCallableDescriptorWithReceiver().getExtensionReceiverParameter().getType());
065            return StackValue.local(AsmUtil.getReceiverIndex(this, getContextDescriptor()), asmType);
066        }
067    
068        @Override
069        public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result, GenerationState state, boolean ignoreNoOuter) {
070            if (getContextDescriptor() == d) {
071                return result != null ? result : StackValue.LOCAL_0;
072            }
073    
074            return getParentContext().lookupInContext(d, result, state, ignoreNoOuter);
075        }
076    
077        @Nullable
078        public StackValue generateReceiver(@NotNull CallableDescriptor descriptor, @NotNull GenerationState state, boolean ignoreNoOuter) {
079            if (getCallableDescriptorWithReceiver() == descriptor) {
080                return getReceiverExpression(state.getTypeMapper());
081            }
082            ReceiverParameterDescriptor parameter = descriptor.getExtensionReceiverParameter();
083            return lookupInContext(parameter, StackValue.LOCAL_0, state, ignoreNoOuter);
084        }
085    
086        @Override
087        public StackValue getOuterExpression(StackValue prefix, boolean ignoreNoOuter) {
088            return getParentContext().getOuterExpression(prefix, false);
089        }
090    
091        @Nullable
092        public Label getMethodStartLabel() {
093            return methodStartLabel;
094        }
095    
096        public void setMethodStartLabel(@NotNull Label methodStartLabel) {
097            this.methodStartLabel = methodStartLabel;
098        }
099    
100        @Nullable
101        public Label getMethodEndLabel() {
102            return methodEndLabel;
103        }
104    
105        public void setMethodEndLabel(@NotNull Label methodEndLabel) {
106            this.methodEndLabel = methodEndLabel;
107        }
108    
109        @Override
110        public String toString() {
111            return "Method: " + getContextDescriptor();
112        }
113    
114        public boolean isInlineFunction() {
115            DeclarationDescriptor descriptor = getContextDescriptor();
116            if (descriptor instanceof SimpleFunctionDescriptor) {
117                return ((SimpleFunctionDescriptor) descriptor).getInlineStrategy().isInline();
118            }
119            return false;
120        }
121    
122        public boolean isInliningLambda() {
123            return isInliningLambda;
124        }
125    
126        @NotNull
127        public FunctionDescriptor getFunctionDescriptor() {
128            return functionDescriptor;
129        }
130    }