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.kotlin.descriptors.impl.SyntheticFieldDescriptor;
030    import org.jetbrains.kotlin.resolve.inline.InlineUtil;
031    import org.jetbrains.org.objectweb.asm.Label;
032    import org.jetbrains.org.objectweb.asm.Type;
033    
034    public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
035        private Label methodStartLabel;
036        private Label methodEndLabel;
037    
038        // Note: in case of code inside property accessors, functionDescriptor will be that accessor,
039        // but CodegenContext#contextDescriptor will be the corresponding property
040        private final FunctionDescriptor functionDescriptor;
041    
042        protected MethodContext(
043                @NotNull FunctionDescriptor functionDescriptor,
044                @NotNull OwnerKind contextKind,
045                @NotNull CodegenContext parentContext,
046                @Nullable MutableClosure closure
047        ) {
048            super(JvmCodegenUtil.getDirectMember(functionDescriptor), contextKind, parentContext, closure,
049                  parentContext.hasThisDescriptor() ? parentContext.getThisDescriptor() : null, null);
050            this.functionDescriptor = functionDescriptor;
051        }
052    
053        @NotNull
054        @Override
055        public CodegenContext getParentContext() {
056            //noinspection ConstantConditions
057            return super.getParentContext();
058        }
059    
060        public StackValue getReceiverExpression(JetTypeMapper typeMapper) {
061            assert getCallableDescriptorWithReceiver() != null;
062            @SuppressWarnings("ConstantConditions")
063            Type asmType = typeMapper.mapType(getCallableDescriptorWithReceiver().getExtensionReceiverParameter().getType());
064            return StackValue.local(AsmUtil.getReceiverIndex(this, getContextDescriptor()), asmType);
065        }
066    
067        @Override
068        public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result, GenerationState state, boolean ignoreNoOuter) {
069            if (d instanceof SyntheticFieldDescriptor) {
070                SyntheticFieldDescriptor fieldDescriptor = (SyntheticFieldDescriptor) d;
071                d = fieldDescriptor.getPropertyDescriptor();
072            }
073            if (getContextDescriptor() == d) {
074                return result != null ? result : StackValue.LOCAL_0;
075            }
076    
077            return getParentContext().lookupInContext(d, result, state, ignoreNoOuter);
078        }
079    
080        @Nullable
081        public StackValue generateReceiver(@NotNull CallableDescriptor descriptor, @NotNull GenerationState state, boolean ignoreNoOuter) {
082            if (getCallableDescriptorWithReceiver() == descriptor) {
083                return getReceiverExpression(state.getTypeMapper());
084            }
085            ReceiverParameterDescriptor parameter = descriptor.getExtensionReceiverParameter();
086            return lookupInContext(parameter, StackValue.LOCAL_0, state, ignoreNoOuter);
087        }
088    
089        @Override
090        public StackValue getOuterExpression(StackValue prefix, boolean ignoreNoOuter) {
091            return getParentContext().getOuterExpression(prefix, false);
092        }
093    
094        @Nullable
095        public Label getMethodStartLabel() {
096            return methodStartLabel;
097        }
098    
099        public void setMethodStartLabel(@NotNull Label methodStartLabel) {
100            this.methodStartLabel = methodStartLabel;
101        }
102    
103        @Nullable
104        public Label getMethodEndLabel() {
105            return methodEndLabel;
106        }
107    
108        public void setMethodEndLabel(@NotNull Label methodEndLabel) {
109            this.methodEndLabel = methodEndLabel;
110        }
111    
112        @Override
113        public String toString() {
114            return "Method: " + getContextDescriptor();
115        }
116    
117        public boolean isInlineMethodContext() {
118            return InlineUtil.isInline(getContextDescriptor());
119        }
120    
121        @NotNull
122        public FunctionDescriptor getFunctionDescriptor() {
123            return functionDescriptor;
124        }
125    }