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