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(@NotNull NameGenerator generator,
081 @NotNull Map<String, String> newTypeMappings,
082 @NotNull AnonymousObjectGeneration anonymousObjectGeneration,
083 @NotNull InlineCallSiteInfo callSiteInfo
084 ) {
085 return new RegeneratedClassContext(this, expressionMap, state, generator,
086 TypeRemapper.createFrom(typeRemapper, newTypeMappings),
087 reifedTypeInliner, isInliningLambda, anonymousObjectGeneration, 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 }