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.serialization;
018
019 import com.google.protobuf.Internal;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.kotlin.descriptors.*;
023
024 public class Flags {
025 private Flags() {}
026
027 // Common
028
029 public static final BooleanFlagField HAS_ANNOTATIONS = FlagField.booleanFirst();
030 public static final FlagField<ProtoBuf.Visibility> VISIBILITY = FlagField.after(HAS_ANNOTATIONS, ProtoBuf.Visibility.values());
031 public static final FlagField<ProtoBuf.Modality> MODALITY = FlagField.after(VISIBILITY, ProtoBuf.Modality.values());
032
033 // Class
034
035 public static final FlagField<ProtoBuf.Class.Kind> CLASS_KIND = FlagField.after(MODALITY, ProtoBuf.Class.Kind.values());
036 public static final BooleanFlagField IS_INNER = FlagField.booleanAfter(CLASS_KIND);
037 public static final BooleanFlagField IS_DATA = FlagField.booleanAfter(IS_INNER);
038
039 // Constructors
040
041 public static final BooleanFlagField IS_SECONDARY = FlagField.booleanAfter(VISIBILITY);
042
043 // Callables
044
045 public static final FlagField<ProtoBuf.MemberKind> MEMBER_KIND = FlagField.after(MODALITY, ProtoBuf.MemberKind.values());
046
047 // Functions
048
049 public static final BooleanFlagField IS_OPERATOR = FlagField.booleanAfter(MEMBER_KIND);
050 public static final BooleanFlagField IS_INFIX = FlagField.booleanAfter(IS_OPERATOR);
051 public static final BooleanFlagField IS_INLINE = FlagField.booleanAfter(IS_INFIX);
052 public static final BooleanFlagField IS_TAILREC = FlagField.booleanAfter(IS_INLINE);
053 public static final BooleanFlagField IS_EXTERNAL_FUNCTION = FlagField.booleanAfter(IS_TAILREC);
054
055 // Properties
056
057 public static final BooleanFlagField IS_VAR = FlagField.booleanAfter(MEMBER_KIND);
058 public static final BooleanFlagField HAS_GETTER = FlagField.booleanAfter(IS_VAR);
059 public static final BooleanFlagField HAS_SETTER = FlagField.booleanAfter(HAS_GETTER);
060 public static final BooleanFlagField IS_CONST = FlagField.booleanAfter(HAS_SETTER);
061 public static final BooleanFlagField IS_LATEINIT = FlagField.booleanAfter(IS_CONST);
062 public static final BooleanFlagField HAS_CONSTANT = FlagField.booleanAfter(IS_LATEINIT);
063
064 // Parameters
065
066 public static final BooleanFlagField DECLARES_DEFAULT_VALUE = FlagField.booleanAfter(HAS_ANNOTATIONS);
067 public static final BooleanFlagField IS_CROSSINLINE = FlagField.booleanAfter(DECLARES_DEFAULT_VALUE);
068 public static final BooleanFlagField IS_NOINLINE = FlagField.booleanAfter(IS_CROSSINLINE);
069
070 // Accessors
071
072 public static final BooleanFlagField IS_NOT_DEFAULT = FlagField.booleanAfter(MODALITY);
073 public static final BooleanFlagField IS_EXTERNAL_ACCESSOR = FlagField.booleanAfter(IS_NOT_DEFAULT);
074
075 // ---
076
077 private static <E> int bitWidth(@NotNull E[] enumEntries) {
078 int length = enumEntries.length - 1;
079 if (length == 0) return 1;
080 for (int i = 31; i >= 0; i--) {
081 if ((length & (1 << i)) != 0) return i + 1;
082 }
083 throw new IllegalStateException("Empty enum: " + enumEntries.getClass());
084 }
085
086 public static int getClassFlags(
087 boolean hasAnnotations,
088 Visibility visibility,
089 Modality modality,
090 ClassKind kind,
091 boolean inner,
092 boolean isCompanionObject,
093 boolean isData
094 ) {
095 return HAS_ANNOTATIONS.toFlags(hasAnnotations)
096 | MODALITY.toFlags(modality(modality))
097 | VISIBILITY.toFlags(visibility(visibility))
098 | CLASS_KIND.toFlags(classKind(kind, isCompanionObject))
099 | IS_INNER.toFlags(inner)
100 | IS_DATA.toFlags(isData)
101 ;
102 }
103
104 private static ProtoBuf.Class.Kind classKind(ClassKind kind, boolean isCompanionObject) {
105 if (isCompanionObject) return ProtoBuf.Class.Kind.COMPANION_OBJECT;
106
107 switch (kind) {
108 case CLASS:
109 return ProtoBuf.Class.Kind.CLASS;
110 case INTERFACE:
111 return ProtoBuf.Class.Kind.INTERFACE;
112 case ENUM_CLASS:
113 return ProtoBuf.Class.Kind.ENUM_CLASS;
114 case ENUM_ENTRY:
115 return ProtoBuf.Class.Kind.ENUM_ENTRY;
116 case ANNOTATION_CLASS:
117 return ProtoBuf.Class.Kind.ANNOTATION_CLASS;
118 case OBJECT:
119 return ProtoBuf.Class.Kind.OBJECT;
120 }
121 throw new IllegalArgumentException("Unknown class kind: " + kind);
122 }
123
124 public static int getConstructorFlags(
125 boolean hasAnnotations,
126 @NotNull Visibility visibility,
127 boolean isSecondary
128 ) {
129 return HAS_ANNOTATIONS.toFlags(hasAnnotations)
130 | VISIBILITY.toFlags(visibility(visibility))
131 | IS_SECONDARY.toFlags(isSecondary)
132 ;
133 }
134
135 public static int getFunctionFlags(
136 boolean hasAnnotations,
137 @NotNull Visibility visibility,
138 @NotNull Modality modality,
139 @NotNull CallableMemberDescriptor.Kind memberKind,
140 boolean isOperator,
141 boolean isInfix,
142 boolean isInline,
143 boolean isTailrec,
144 boolean isExternal
145 ) {
146 return HAS_ANNOTATIONS.toFlags(hasAnnotations)
147 | VISIBILITY.toFlags(visibility(visibility))
148 | MODALITY.toFlags(modality(modality))
149 | MEMBER_KIND.toFlags(memberKind(memberKind))
150 | IS_OPERATOR.toFlags(isOperator)
151 | IS_INFIX.toFlags(isInfix)
152 | IS_INLINE.toFlags(isInline)
153 | IS_TAILREC.toFlags(isTailrec)
154 | IS_EXTERNAL_FUNCTION.toFlags(isExternal)
155 ;
156 }
157
158 public static int getPropertyFlags(
159 boolean hasAnnotations,
160 @NotNull Visibility visibility,
161 @NotNull Modality modality,
162 @NotNull CallableMemberDescriptor.Kind memberKind,
163 boolean isVar,
164 boolean hasGetter,
165 boolean hasSetter,
166 boolean hasConstant,
167 boolean isConst,
168 boolean lateInit
169 ) {
170 return HAS_ANNOTATIONS.toFlags(hasAnnotations)
171 | VISIBILITY.toFlags(visibility(visibility))
172 | MODALITY.toFlags(modality(modality))
173 | MEMBER_KIND.toFlags(memberKind(memberKind))
174 | IS_VAR.toFlags(isVar)
175 | HAS_GETTER.toFlags(hasGetter)
176 | HAS_SETTER.toFlags(hasSetter)
177 | IS_CONST.toFlags(isConst)
178 | IS_LATEINIT.toFlags(lateInit)
179 | HAS_CONSTANT.toFlags(hasConstant)
180 ;
181 }
182
183 public static int getAccessorFlags(
184 boolean hasAnnotations,
185 @NotNull Visibility visibility,
186 @NotNull Modality modality,
187 boolean isNotDefault,
188 boolean isExternal
189 ) {
190 return HAS_ANNOTATIONS.toFlags(hasAnnotations)
191 | MODALITY.toFlags(modality(modality))
192 | VISIBILITY.toFlags(visibility(visibility))
193 | IS_NOT_DEFAULT.toFlags(isNotDefault)
194 | IS_EXTERNAL_ACCESSOR.toFlags(isExternal)
195 ;
196 }
197
198 @NotNull
199 private static ProtoBuf.Visibility visibility(@NotNull Visibility visibility) {
200 if (visibility == Visibilities.INTERNAL) {
201 return ProtoBuf.Visibility.INTERNAL;
202 }
203 else if (visibility == Visibilities.PUBLIC) {
204 return ProtoBuf.Visibility.PUBLIC;
205 }
206 else if (visibility == Visibilities.PRIVATE) {
207 return ProtoBuf.Visibility.PRIVATE;
208 }
209 else if (visibility == Visibilities.PRIVATE_TO_THIS) {
210 return ProtoBuf.Visibility.PRIVATE_TO_THIS;
211 }
212 else if (visibility == Visibilities.PROTECTED) {
213 return ProtoBuf.Visibility.PROTECTED;
214 }
215 else if (visibility == Visibilities.LOCAL) {
216 return ProtoBuf.Visibility.LOCAL;
217 }
218 throw new IllegalArgumentException("Unknown visibility: " + visibility);
219 }
220
221 @NotNull
222 private static ProtoBuf.Modality modality(@NotNull Modality modality) {
223 switch (modality) {
224 case FINAL:
225 return ProtoBuf.Modality.FINAL;
226 case OPEN:
227 return ProtoBuf.Modality.OPEN;
228 case ABSTRACT:
229 return ProtoBuf.Modality.ABSTRACT;
230 case SEALED:
231 return ProtoBuf.Modality.SEALED;
232 }
233 throw new IllegalArgumentException("Unknown modality: " + modality);
234 }
235
236 @NotNull
237 private static ProtoBuf.MemberKind memberKind(@NotNull CallableMemberDescriptor.Kind kind) {
238 switch (kind) {
239 case DECLARATION:
240 return ProtoBuf.MemberKind.DECLARATION;
241 case FAKE_OVERRIDE:
242 return ProtoBuf.MemberKind.FAKE_OVERRIDE;
243 case DELEGATION:
244 return ProtoBuf.MemberKind.DELEGATION;
245 case SYNTHESIZED:
246 return ProtoBuf.MemberKind.SYNTHESIZED;
247 }
248 throw new IllegalArgumentException("Unknown member kind: " + kind);
249 }
250
251 public static int getValueParameterFlags(
252 boolean hasAnnotations,
253 boolean declaresDefaultValue,
254 boolean isCrossinline,
255 boolean isNoinline
256 ) {
257 return HAS_ANNOTATIONS.toFlags(hasAnnotations)
258 | DECLARES_DEFAULT_VALUE.toFlags(declaresDefaultValue)
259 | IS_CROSSINLINE.toFlags(isCrossinline)
260 | IS_NOINLINE.toFlags(isNoinline)
261 ;
262 }
263
264 // Infrastructure
265
266 public static abstract class FlagField<E> {
267 public static <E extends Internal.EnumLite> FlagField<E> after(FlagField<?> previousField, E[] values) {
268 int offset = previousField.offset + previousField.bitWidth;
269 return new EnumLiteFlagField<E>(offset, values);
270 }
271
272 public static <E extends Internal.EnumLite> FlagField<E> first(E[] values) {
273 return new EnumLiteFlagField<E>(0, values);
274 }
275
276 public static BooleanFlagField booleanFirst() {
277 return new BooleanFlagField(0);
278 }
279
280 public static BooleanFlagField booleanAfter(FlagField<?> previousField) {
281 int offset = previousField.offset + previousField.bitWidth;
282 return new BooleanFlagField(offset);
283 }
284
285 private final int offset;
286 private final int bitWidth;
287 private final E[] values;
288
289 private FlagField(int offset, E[] values) {
290 this.offset = offset;
291 this.bitWidth = bitWidth(values);
292 this.values = values;
293 }
294
295 @Nullable
296 public E get(int flags) {
297 int maskUnshifted = (1 << bitWidth) - 1;
298 int mask = maskUnshifted << offset;
299 int value = (flags & mask) >> offset;
300 for (E e : values) {
301 if (getIntValue(e) == value) {
302 return e;
303 }
304 }
305 return null;
306 }
307
308 public int toFlags(E value) {
309 return getIntValue(value) << offset;
310 }
311
312 protected abstract int getIntValue(E value);
313
314 }
315
316 public static class BooleanFlagField extends FlagField<Boolean> {
317 private static final Boolean[] BOOLEAN = { false, true };
318
319 public BooleanFlagField(int offset) {
320 super(offset, BOOLEAN);
321 }
322
323 @Override
324 protected int getIntValue(Boolean value) {
325 return value ? 1 : 0;
326 }
327
328 @NotNull
329 @Override
330 public Boolean get(int flags) {
331 //noinspection ConstantConditions
332 return super.get(flags);
333 }
334 }
335
336 private static class EnumLiteFlagField<E extends Internal.EnumLite> extends FlagField<E> {
337 public EnumLiteFlagField(int offset, E[] values) {
338 super(offset, values);
339 }
340
341 @Override
342 protected int getIntValue(E value) {
343 return value.getNumber();
344 }
345 }
346
347 }