001    /*
002     * Copyright 2010-2013 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.jet.codegen.context;
018    
019    import org.jetbrains.jet.codegen.JvmCodegenUtil;
020    import org.jetbrains.org.objectweb.asm.Type;
021    import org.jetbrains.jet.codegen.ExpressionCodegen;
022    import org.jetbrains.jet.codegen.StackValue;
023    import org.jetbrains.jet.codegen.binding.MutableClosure;
024    import org.jetbrains.jet.codegen.state.GenerationState;
025    import org.jetbrains.jet.lang.descriptors.*;
026    import org.jetbrains.jet.lang.resolve.BindingContext;
027    import org.jetbrains.jet.lang.resolve.java.JvmAbi;
028    import org.jetbrains.jet.lang.types.JetType;
029    
030    import static org.jetbrains.jet.codegen.AsmUtil.CAPTURED_RECEIVER_FIELD;
031    import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
032    
033    public interface LocalLookup {
034        boolean lookupLocal(DeclarationDescriptor descriptor);
035    
036        enum LocalLookupCase {
037            VAR {
038                @Override
039                public boolean isCase(DeclarationDescriptor d) {
040                    return d instanceof VariableDescriptor && !(d instanceof PropertyDescriptor);
041                }
042    
043                @Override
044                public StackValue innerValue(
045                        DeclarationDescriptor d,
046                        LocalLookup localLookup,
047                        GenerationState state,
048                        MutableClosure closure,
049                        Type classType
050                ) {
051                    VariableDescriptor vd = (VariableDescriptor) d;
052    
053                    boolean idx = localLookup != null && localLookup.lookupLocal(vd);
054                    if (!idx) return null;
055    
056                    Type sharedVarType = state.getTypeMapper().getSharedVarType(vd);
057                    Type localType = state.getTypeMapper().mapType(vd);
058                    Type type = sharedVarType != null ? sharedVarType : localType;
059    
060                    String fieldName = "$" + vd.getName();
061                    StackValue innerValue = sharedVarType != null
062                                            ? StackValue.fieldForSharedVar(localType, classType, fieldName)
063                                            : StackValue.field(type, classType, fieldName, false);
064    
065                    closure.recordField(fieldName, type);
066                    closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, type));
067    
068                    return innerValue;
069                }
070            },
071    
072            LOCAL_NAMED_FUNCTION {
073                @Override
074                public boolean isCase(DeclarationDescriptor d) {
075                    return isLocalNamedFun(d);
076                }
077    
078                @Override
079                public StackValue innerValue(
080                        DeclarationDescriptor d,
081                        LocalLookup localLookup,
082                        GenerationState state,
083                        MutableClosure closure,
084                        Type classType
085                ) {
086                    FunctionDescriptor vd = (FunctionDescriptor) d;
087    
088                    boolean idx = localLookup != null && localLookup.lookupLocal(vd);
089                    if (!idx) return null;
090    
091                    BindingContext bindingContext = state.getBindingContext();
092                    Type localType = asmTypeForAnonymousClass(bindingContext, vd);
093    
094                    MutableClosure localFunClosure = bindingContext.get(CLOSURE, bindingContext.get(CLASS_FOR_FUNCTION, vd));
095                    if (localFunClosure != null && JvmCodegenUtil.isConst(localFunClosure)) {
096                        // This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance
097                        // (instead of passing this instance to the constructor and storing as a field)
098                        return StackValue.field(localType, localType, JvmAbi.INSTANCE_FIELD, true);
099                    }
100    
101                    String fieldName = "$" + vd.getName();
102                    StackValue innerValue = StackValue.field(localType, classType, fieldName, false);
103    
104                    closure.recordField(fieldName, localType);
105                    closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType));
106    
107                    return innerValue;
108                }
109            },
110    
111            RECEIVER {
112                @Override
113                public boolean isCase(DeclarationDescriptor d) {
114                    return d instanceof CallableDescriptor;
115                }
116    
117                @Override
118                public StackValue innerValue(
119                        DeclarationDescriptor d,
120                        LocalLookup enclosingLocalLookup,
121                        GenerationState state,
122                        MutableClosure closure,
123                        Type classType
124                ) {
125                    if (closure.getEnclosingReceiverDescriptor() != d) return null;
126    
127                    JetType receiverType = ((CallableDescriptor) d).getReceiverParameter().getType();
128                    Type type = state.getTypeMapper().mapType(receiverType);
129                    StackValue innerValue = StackValue.field(type, classType, CAPTURED_RECEIVER_FIELD, false);
130                    closure.setCaptureReceiver();
131    
132                    return innerValue;
133                }
134    
135                @Override
136                public StackValue outerValue(EnclosedValueDescriptor d, ExpressionCodegen expressionCodegen) {
137                    CallableDescriptor descriptor = (CallableDescriptor) d.getDescriptor();
138                    return StackValue.local(descriptor.getExpectedThisObject() != null ? 1 : 0, d.getType());
139                }
140            };
141    
142            public abstract boolean isCase(DeclarationDescriptor d);
143    
144            public abstract StackValue innerValue(
145                    DeclarationDescriptor d,
146                    LocalLookup localLookup,
147                    GenerationState state,
148                    MutableClosure closure,
149                    Type classType
150            );
151    
152            public StackValue outerValue(EnclosedValueDescriptor d, ExpressionCodegen expressionCodegen) {
153                int idx = expressionCodegen.lookupLocalIndex(d.getDescriptor());
154                assert idx != -1;
155    
156                return StackValue.local(idx, d.getType());
157            }
158        }
159    }