001    /*
002     * Copyright 2010-2015 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.kotlin.codegen.inline;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.kotlin.codegen.state.GenerationState;
022    
023    import java.util.Collections;
024    import java.util.HashMap;
025    import java.util.Map;
026    
027    public class InliningContext {
028    
029        @Nullable
030        private final InliningContext parent;
031    
032        public final Map<Integer, LambdaInfo> expressionMap;
033    
034        public final GenerationState state;
035    
036        public final NameGenerator nameGenerator;
037    
038        public final TypeRemapper typeRemapper;
039    
040        public final ReifiedTypeInliner reifedTypeInliner;
041    
042        public final boolean isInliningLambda;
043    
044        public final boolean classRegeneration;
045    
046        protected InliningContext(
047                @Nullable InliningContext parent,
048                @NotNull Map<Integer, LambdaInfo> map,
049                @NotNull GenerationState state,
050                @NotNull NameGenerator nameGenerator,
051                @NotNull TypeRemapper typeRemapper,
052                @NotNull ReifiedTypeInliner reifedTypeInliner,
053                boolean isInliningLambda,
054                boolean classRegeneration
055        ) {
056            this.parent = parent;
057            expressionMap = map;
058            this.state = state;
059            this.nameGenerator = nameGenerator;
060            this.typeRemapper = typeRemapper;
061            this.reifedTypeInliner = reifedTypeInliner;
062            this.isInliningLambda = isInliningLambda;
063            this.classRegeneration = classRegeneration;
064        }
065    
066        public InliningContext subInline(NameGenerator generator) {
067            return subInline(generator, Collections.<String, String>emptyMap());
068        }
069    
070        public InliningContext subInlineLambda(LambdaInfo lambdaInfo) {
071            Map<String, String> map = new HashMap<String, String>();
072            map.put(lambdaInfo.getLambdaClassType().getInternalName(), null); //mark lambda inlined
073            return subInline(nameGenerator.subGenerator("lambda"), map, true);
074        }
075    
076        private InliningContext subInline(NameGenerator generator, Map<String, String> additionalTypeMappings) {
077            return subInline(generator, additionalTypeMappings, isInliningLambda);
078        }
079    
080        public InliningContext subInlineWithClassRegeneration(
081                @NotNull NameGenerator generator,
082                @NotNull Map<String, String> newTypeMappings,
083                @NotNull InlineCallSiteInfo callSiteInfo
084        ) {
085            return new RegeneratedClassContext(this, expressionMap, state, generator,
086                                               TypeRemapper.createFrom(typeRemapper, newTypeMappings),
087                                               reifedTypeInliner, isInliningLambda, callSiteInfo);
088        }
089    
090        public InliningContext subInline(NameGenerator generator, Map<String, String> additionalTypeMappings, boolean isInliningLambda) {
091            return subInline(generator, additionalTypeMappings, isInliningLambda, classRegeneration);
092        }
093    
094        private InliningContext subInline(
095                NameGenerator generator,
096                Map<String, String> additionalTypeMappings,
097                boolean isInliningLambda,
098                boolean isRegeneration
099        ) {
100            //isInliningLambda && !this.isInliningLambda for root inline lambda
101            return new InliningContext(this, expressionMap, state, generator,
102                                       TypeRemapper.createFrom(
103                                               typeRemapper,
104                                               additionalTypeMappings,
105                                               //root inline lambda
106                                               isInliningLambda && !this.isInliningLambda
107                                       ),
108                                       reifedTypeInliner, isInliningLambda, isRegeneration);
109        }
110    
111        public boolean isRoot() {
112            return parent == null;
113        }
114    
115        @NotNull
116        public RootInliningContext getRoot() {
117            if (isRoot()) {
118                return (RootInliningContext) this;
119            }
120            else {
121                return parent.getRoot();
122            }
123        }
124    
125        @Nullable
126        public InliningContext getParent() {
127            return parent;
128        }
129    
130        public boolean isInliningLambdaRootContext() {
131            //noinspection ConstantConditions
132            return isInliningLambda && !getParent().isInliningLambda;
133        }
134    
135        public InlineCallSiteInfo getCallSiteInfo() {
136            assert parent != null : "At least root context should return proper value";
137            return parent.getCallSiteInfo();
138        }
139    }