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