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