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