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