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.kotlin.codegen.ExpressionCodegen;
021    import org.jetbrains.kotlin.codegen.JvmCodegenUtil;
022    import org.jetbrains.kotlin.codegen.StackValue;
023    import org.jetbrains.kotlin.codegen.binding.MutableClosure;
024    import org.jetbrains.kotlin.codegen.state.GenerationState;
025    import org.jetbrains.kotlin.descriptors.*;
026    import org.jetbrains.kotlin.load.java.JvmAbi;
027    import org.jetbrains.kotlin.resolve.BindingContext;
028    import org.jetbrains.kotlin.types.KotlinType;
029    import org.jetbrains.org.objectweb.asm.Type;
030    
031    import static org.jetbrains.kotlin.codegen.AsmUtil.CAPTURED_RECEIVER_FIELD;
032    import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
033    import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isLocalFunction;
034    
035    public interface LocalLookup {
036        boolean lookupLocal(DeclarationDescriptor descriptor);
037    
038        enum LocalLookupCase {
039            VAR {
040                @Override
041                public boolean isCase(DeclarationDescriptor d) {
042                    return d instanceof VariableDescriptor && !(d instanceof PropertyDescriptor);
043                }
044    
045                @Override
046                public StackValue.StackValueWithSimpleReceiver innerValue(
047                        DeclarationDescriptor d,
048                        LocalLookup localLookup,
049                        GenerationState state,
050                        MutableClosure closure,
051                        Type classType
052                ) {
053                    VariableDescriptor vd = (VariableDescriptor) d;
054    
055                    boolean idx = localLookup != null && localLookup.lookupLocal(vd);
056                    if (!idx) return null;
057    
058                    VariableDescriptor delegateVariableDescriptor = state.getBindingContext().get(LOCAL_VARIABLE_DELEGATE, vd);
059                    Type sharedVarType = state.getTypeMapper().getSharedVarType(vd);
060                    Type localType = state.getTypeMapper().mapType(delegateVariableDescriptor != null ? delegateVariableDescriptor : vd);
061                    Type type = sharedVarType != null ? sharedVarType : localType;
062    
063                    String fieldName = "$" + vd.getName();
064                    StackValue.Local thiz = StackValue.LOCAL_0;
065    
066                    StackValue.StackValueWithSimpleReceiver innerValue;
067                    EnclosedValueDescriptor enclosedValueDescriptor;
068                    if (sharedVarType != null) {
069                        StackValue.Field wrapperValue = StackValue.receiverWithRefWrapper(localType, classType, fieldName, thiz, vd);
070                        innerValue = StackValue.fieldForSharedVar(localType, classType, fieldName, wrapperValue);
071                        enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, wrapperValue, type);
072                    }
073                    else {
074                        innerValue = StackValue.field(type, classType, fieldName, false, thiz, vd);
075                        enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, type);
076                    }
077    
078                    closure.recordField(fieldName, type);
079                    closure.captureVariable(enclosedValueDescriptor);
080    
081                    return innerValue;
082                }
083            },
084    
085            LOCAL_NAMED_FUNCTION {
086                @Override
087                public boolean isCase(DeclarationDescriptor d) {
088                    return isLocalFunction(d);
089                }
090    
091                @Override
092                public StackValue.StackValueWithSimpleReceiver innerValue(
093                        DeclarationDescriptor d,
094                        LocalLookup localLookup,
095                        GenerationState state,
096                        MutableClosure closure,
097                        Type classType
098                ) {
099                    FunctionDescriptor vd = (FunctionDescriptor) d;
100    
101                    boolean idx = localLookup != null && localLookup.lookupLocal(vd);
102                    if (!idx) return null;
103    
104                    BindingContext bindingContext = state.getBindingContext();
105                    Type localType = asmTypeForAnonymousClass(bindingContext, vd);
106    
107                    MutableClosure localFunClosure = bindingContext.get(CLOSURE, bindingContext.get(CLASS_FOR_CALLABLE, vd));
108                    if (localFunClosure != null && JvmCodegenUtil.isConst(localFunClosure)) {
109                        // This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance
110                        // (instead of passing this instance to the constructor and storing as a field)
111                        return StackValue.field(localType, localType, JvmAbi.INSTANCE_FIELD, true, StackValue.LOCAL_0, vd);
112                    }
113    
114                    String fieldName = "$" + vd.getName();
115                    StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(localType, classType, fieldName, false,
116                                                                                          StackValue.LOCAL_0, vd);
117    
118                    closure.recordField(fieldName, localType);
119                    closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType));
120    
121                    return innerValue;
122                }
123            },
124    
125            RECEIVER {
126                @Override
127                public boolean isCase(DeclarationDescriptor d) {
128                    return d instanceof ReceiverParameterDescriptor;
129                }
130    
131                @Override
132                public StackValue.StackValueWithSimpleReceiver innerValue(
133                        DeclarationDescriptor d,
134                        LocalLookup enclosingLocalLookup,
135                        GenerationState state,
136                        MutableClosure closure,
137                        Type classType
138                ) {
139                    if (closure.getEnclosingReceiverDescriptor() != d) {
140                        return null;
141                    }
142    
143                    KotlinType receiverType = closure.getEnclosingReceiverDescriptor().getType();
144                    Type type = state.getTypeMapper().mapType(receiverType);
145                    StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(type, classType, CAPTURED_RECEIVER_FIELD, false,
146                                                                                          StackValue.LOCAL_0, d);
147                    closure.setCaptureReceiver();
148    
149                    return innerValue;
150                }
151    
152                @NotNull
153                @Override
154                public StackValue outerValue(@NotNull EnclosedValueDescriptor d, @NotNull ExpressionCodegen codegen) {
155                    CallableDescriptor descriptor = (CallableDescriptor) d.getDescriptor();
156                    return StackValue.local(descriptor.getDispatchReceiverParameter() != null ? 1 : 0, d.getType());
157                }
158            };
159    
160            public abstract boolean isCase(DeclarationDescriptor d);
161    
162            public abstract StackValue.StackValueWithSimpleReceiver innerValue(
163                    DeclarationDescriptor d,
164                    LocalLookup localLookup,
165                    GenerationState state,
166                    MutableClosure closure,
167                    Type classType
168            );
169    
170            @NotNull
171            public StackValue outerValue(@NotNull EnclosedValueDescriptor d, @NotNull ExpressionCodegen codegen) {
172                DeclarationDescriptor declarationDescriptor = d.getDescriptor();
173                int idx = codegen.lookupLocalIndex(declarationDescriptor);
174                if (idx >= 0) {
175                    return StackValue.local(idx, d.getType());
176                }
177                else {
178                    assert declarationDescriptor != null : "No declaration descriptor for " + d;
179                    StackValue capturedValue = codegen.findCapturedValue(declarationDescriptor);
180                    assert capturedValue != null : "Unresolved captured value for " + d;
181                    return capturedValue;
182                }
183            }
184        }
185    }