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.inline;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.jet.codegen.AsmUtil;
022    import org.jetbrains.jet.codegen.StackValue;
023    import org.jetbrains.jet.codegen.binding.CalculatedClosure;
024    import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor;
025    import org.jetbrains.jet.codegen.state.JetTypeMapper;
026    import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
027    import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
028    import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
029    import org.jetbrains.jet.lang.psi.JetFunctionLiteral;
030    import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
031    import org.jetbrains.jet.lang.resolve.BindingContext;
032    import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
033    import org.jetbrains.org.objectweb.asm.Type;
034    import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode;
035    import org.jetbrains.org.objectweb.asm.tree.MethodNode;
036    
037    import java.util.ArrayList;
038    import java.util.Arrays;
039    import java.util.List;
040    
041    import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
042    
043    public class LambdaInfo implements CapturedParamOwner, LabelOwner {
044    
045        public final JetFunctionLiteralExpression expression;
046    
047        @NotNull
048        private final JetTypeMapper typeMapper;
049    
050        @Nullable
051        public final String labelName;
052    
053        private final CalculatedClosure closure;
054    
055        private MethodNode node;
056    
057        private List<CapturedParamDesc> capturedVars;
058    
059        private final FunctionDescriptor functionDescriptor;
060    
061        private final ClassDescriptor classDescriptor;
062    
063        private final Type closureClassType;
064    
065        LambdaInfo(@NotNull JetFunctionLiteralExpression expression, @NotNull JetTypeMapper typeMapper, @Nullable String labelName) {
066            this.expression = expression;
067            this.typeMapper = typeMapper;
068            this.labelName = labelName;
069            BindingContext bindingContext = typeMapper.getBindingContext();
070            functionDescriptor = bindingContext.get(BindingContext.FUNCTION, expression.getFunctionLiteral());
071            assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText();
072    
073            classDescriptor = anonymousClassForFunction(bindingContext, functionDescriptor);
074            closureClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor);
075    
076            closure = bindingContext.get(CLOSURE, classDescriptor);
077            assert closure != null : "Closure for lambda should be not null " + expression.getText();
078        }
079    
080        public MethodNode getNode() {
081            return node;
082        }
083    
084        public void setNode(MethodNode node) {
085            this.node = node;
086        }
087    
088        public FunctionDescriptor getFunctionDescriptor() {
089            return functionDescriptor;
090        }
091    
092        public JetFunctionLiteral getFunctionLiteral() {
093            return expression.getFunctionLiteral();
094        }
095    
096        public ClassDescriptor getClassDescriptor() {
097            return classDescriptor;
098        }
099    
100        public Type getLambdaClassType() {
101            return closureClassType;
102        }
103    
104        public List<CapturedParamDesc> getCapturedVars() {
105            //lazy initialization cause it would be calculated after object creation
106            if (capturedVars == null) {
107                capturedVars = new ArrayList<CapturedParamDesc>();
108    
109                if (closure.getCaptureThis() != null) {
110                    Type type = typeMapper.mapType(closure.getCaptureThis());
111                    EnclosedValueDescriptor descriptor =
112                            new EnclosedValueDescriptor(AsmUtil.CAPTURED_THIS_FIELD,
113                                                        null,
114                                                        StackValue.field(type, closureClassType, AsmUtil.CAPTURED_THIS_FIELD, false,
115                                                                         StackValue.LOCAL_0),
116                                                        type);
117                    capturedVars.add(getCapturedParamInfo(descriptor));
118                }
119    
120                if (closure.getCaptureReceiverType() != null) {
121                    Type type = typeMapper.mapType(closure.getCaptureReceiverType());
122                    EnclosedValueDescriptor descriptor =
123                            new EnclosedValueDescriptor(
124                                    AsmUtil.CAPTURED_RECEIVER_FIELD,
125                                    null,
126                                    StackValue.field(type, closureClassType, AsmUtil.CAPTURED_RECEIVER_FIELD, false,
127                                                     StackValue.LOCAL_0),
128                                    type);
129                    capturedVars.add(getCapturedParamInfo(descriptor));
130                }
131    
132                for (EnclosedValueDescriptor descriptor : closure.getCaptureVariables().values()) {
133                    capturedVars.add(getCapturedParamInfo(descriptor));
134                }
135            }
136            return capturedVars;
137        }
138    
139        @NotNull
140        private CapturedParamDesc getCapturedParamInfo(@NotNull EnclosedValueDescriptor descriptor) {
141            return CapturedParamDesc.createDesc(this, descriptor.getFieldName(), descriptor.getType());
142        }
143    
144        @NotNull
145        public List<Type> getInvokeParamsWithoutCaptured() {
146            Type[] types = typeMapper.mapSignature(functionDescriptor).getAsmMethod().getArgumentTypes();
147            return Arrays.asList(types);
148        }
149    
150        @NotNull
151        public Parameters addAllParameters(FieldRemapper remapper) {
152            ParametersBuilder builder = ParametersBuilder.newBuilder();
153            //add skipped this cause inlined lambda doesn't have it
154            builder.addThis(AsmTypeConstants.OBJECT_TYPE, true).setLambda(this);
155    
156            List<ValueParameterDescriptor> valueParameters = getFunctionDescriptor().getValueParameters();
157            for (ValueParameterDescriptor parameter : valueParameters) {
158                Type type = typeMapper.mapType(parameter.getType());
159                builder.addNextParameter(type, false, null);
160            }
161    
162            for (CapturedParamDesc info : getCapturedVars()) {
163                CapturedParamInfo field = remapper.findField(new FieldInsnNode(0, info.getContainingLambdaName(), info.getFieldName(), ""));
164                builder.addCapturedParam(field, info.getFieldName());
165            }
166    
167            return builder.buildParameters();
168        }
169    
170        @Override
171        public Type getType() {
172            return closureClassType;
173        }
174    
175        @Override
176        public boolean isMyLabel(@NotNull String name) {
177            return name.equals(labelName);
178        }
179    
180    }