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 // Callables
040
041 // TODO: use these flags
042 public static final BooleanFlagField RESERVED_1 = FlagField.booleanAfter(MODALITY);
043 public static final BooleanFlagField RESERVED_2 = FlagField.booleanAfter(RESERVED_1);
044
045 public static final FlagField<ProtoBuf.MemberKind> MEMBER_KIND = FlagField.after(RESERVED_2, ProtoBuf.MemberKind.values());
046
047 // Constructors
048
049 public static final BooleanFlagField IS_SECONDARY = FlagField.booleanAfter(VISIBILITY);
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
059 // Properties
060
061 public static final BooleanFlagField IS_VAR = FlagField.booleanAfter(MEMBER_KIND);
062 public static final BooleanFlagField HAS_GETTER = FlagField.booleanAfter(IS_VAR);
063 public static final BooleanFlagField HAS_SETTER = FlagField.booleanAfter(HAS_GETTER);
064 public static final BooleanFlagField IS_CONST = FlagField.booleanAfter(HAS_SETTER);
065 public static final BooleanFlagField IS_LATEINIT = FlagField.booleanAfter(IS_CONST);
066 public static final BooleanFlagField HAS_CONSTANT = FlagField.booleanAfter(IS_LATEINIT);
067
068 // Parameters
069
070 public static final BooleanFlagField DECLARES_DEFAULT_VALUE = FlagField.booleanAfter(HAS_ANNOTATIONS);
071 public static final BooleanFlagField IS_CROSSINLINE = FlagField.booleanAfter(DECLARES_DEFAULT_VALUE);
072 public static final BooleanFlagField IS_NOINLINE = FlagField.booleanAfter(IS_CROSSINLINE);
073
074 // Accessors
075
076 // It's important that this flag is negated: "is NOT default" instead of "is default"
077 public static final BooleanFlagField IS_NOT_DEFAULT = FlagField.booleanAfter(MODALITY);
078 public static final BooleanFlagField IS_EXTERNAL_ACCESSOR = FlagField.booleanAfter(IS_NOT_DEFAULT);
079
080 // ---
081
082 private static <E> int bitWidth(@NotNull E[] enumEntries) {
083 int length = enumEntries.length - 1;
084 if (length == 0) return 1;
085 for (int i = 31; i >= 0; i--) {
086 if ((length & (1 << i)) != 0) return i + 1;
087 }
088 throw new IllegalStateException("Empty enum: " + enumEntries.getClass());
089 }
090
091 public static int getClassFlags(
092 boolean hasAnnotations,
093 Visibility visibility,
094 Modality modality,
095 ClassKind kind,
096 boolean inner,
097 boolean isCompanionObject,
098 boolean isData
099 ) {
100 return HAS_ANNOTATIONS.toFlags(hasAnnotations)
101 | MODALITY.toFlags(modality(modality))
102 | VISIBILITY.toFlags(visibility(visibility))
103 | CLASS_KIND.toFlags(classKind(kind, isCompanionObject))
104 | IS_INNER.toFlags(inner)
105 | IS_DATA.toFlags(isData)
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 ) {
151 return HAS_ANNOTATIONS.toFlags(hasAnnotations)
152 | VISIBILITY.toFlags(visibility(visibility))
153 | MODALITY.toFlags(modality(modality))
154 | MEMBER_KIND.toFlags(memberKind(memberKind))
155 | IS_OPERATOR.toFlags(isOperator)
156 | IS_INFIX.toFlags(isInfix)
157 | IS_INLINE.toFlags(isInline)
158 | IS_TAILREC.toFlags(isTailrec)
159 | IS_EXTERNAL_FUNCTION.toFlags(isExternal)
160 ;
161 }
162
163 public static int getPropertyFlags(
164 boolean hasAnnotations,
165 @NotNull Visibility visibility,
166 @NotNull Modality modality,
167 @NotNull CallableMemberDescriptor.Kind memberKind,
168 boolean isVar,
169 boolean hasGetter,
170 boolean hasSetter,
171 boolean hasConstant,
172 boolean isConst,
173 boolean lateInit
174 ) {
175 return HAS_ANNOTATIONS.toFlags(hasAnnotations)
176 | VISIBILITY.toFlags(visibility(visibility))
177 | MODALITY.toFlags(modality(modality))
178 | MEMBER_KIND.toFlags(memberKind(memberKind))
179 | IS_VAR.toFlags(isVar)
180 | HAS_GETTER.toFlags(hasGetter)
181 | HAS_SETTER.toFlags(hasSetter)
182 | IS_CONST.toFlags(isConst)
183 | IS_LATEINIT.toFlags(lateInit)
184 | HAS_CONSTANT.toFlags(hasConstant)
185 ;
186 }
187
188 public static int getAccessorFlags(
189 boolean hasAnnotations,
190 @NotNull Visibility visibility,
191 @NotNull Modality modality,
192 boolean isNotDefault,
193 boolean isExternal
194 ) {
195 return HAS_ANNOTATIONS.toFlags(hasAnnotations)
196 | MODALITY.toFlags(modality(modality))
197 | VISIBILITY.toFlags(visibility(visibility))
198 | IS_NOT_DEFAULT.toFlags(isNotDefault)
199 | IS_EXTERNAL_ACCESSOR.toFlags(isExternal)
200 ;
201 }
202
203 @NotNull
204 private static ProtoBuf.Visibility visibility(@NotNull Visibility visibility) {
205 if (visibility == Visibilities.INTERNAL) {
206 return ProtoBuf.Visibility.INTERNAL;
207 }
208 else if (visibility == Visibilities.PUBLIC) {
209 return ProtoBuf.Visibility.PUBLIC;
210 }
211 else if (visibility == Visibilities.PRIVATE) {
212 return ProtoBuf.Visibility.PRIVATE;
213 }
214 else if (visibility == Visibilities.PRIVATE_TO_THIS) {
215 return ProtoBuf.Visibility.PRIVATE_TO_THIS;
216 }
217 else if (visibility == Visibilities.PROTECTED) {
218 return ProtoBuf.Visibility.PROTECTED;
219 }
220 else if (visibility == Visibilities.LOCAL) {
221 return ProtoBuf.Visibility.LOCAL;
222 }
223 throw new IllegalArgumentException("Unknown visibility: " + visibility);
224 }
225
226 @NotNull
227 private static ProtoBuf.Modality modality(@NotNull Modality modality) {
228 switch (modality) {
229 case FINAL:
230 return ProtoBuf.Modality.FINAL;
231 case OPEN:
232 return ProtoBuf.Modality.OPEN;
233 case ABSTRACT:
234 return ProtoBuf.Modality.ABSTRACT;
235 case SEALED:
236 return ProtoBuf.Modality.SEALED;
237 }
238 throw new IllegalArgumentException("Unknown modality: " + modality);
239 }
240
241 @NotNull
242 private static ProtoBuf.MemberKind memberKind(@NotNull CallableMemberDescriptor.Kind kind) {
243 switch (kind) {
244 case DECLARATION:
245 return ProtoBuf.MemberKind.DECLARATION;
246 case FAKE_OVERRIDE:
247 return ProtoBuf.MemberKind.FAKE_OVERRIDE;
248 case DELEGATION:
249 return ProtoBuf.MemberKind.DELEGATION;
250 case SYNTHESIZED:
251 return ProtoBuf.MemberKind.SYNTHESIZED;
252 }
253 throw new IllegalArgumentException("Unknown member kind: " + kind);
254 }
255
256 public static int getValueParameterFlags(
257 boolean hasAnnotations,
258 boolean declaresDefaultValue,
259 boolean isCrossinline,
260 boolean isNoinline
261 ) {
262 return HAS_ANNOTATIONS.toFlags(hasAnnotations)
263 | DECLARES_DEFAULT_VALUE.toFlags(declaresDefaultValue)
264 | IS_CROSSINLINE.toFlags(isCrossinline)
265 | IS_NOINLINE.toFlags(isNoinline)
266 ;
267 }
268
269 // Infrastructure
270
271 public static abstract class FlagField<E> {
272 public static <E extends Internal.EnumLite> FlagField<E> after(FlagField<?> previousField, E[] values) {
273 int offset = previousField.offset + previousField.bitWidth;
274 return new EnumLiteFlagField<E>(offset, values);
275 }
276
277 public static <E extends Internal.EnumLite> FlagField<E> first(E[] values) {
278 return new EnumLiteFlagField<E>(0, values);
279 }
280
281 public static BooleanFlagField booleanFirst() {
282 return new BooleanFlagField(0);
283 }
284
285 public static BooleanFlagField booleanAfter(FlagField<?> previousField) {
286 int offset = previousField.offset + previousField.bitWidth;
287 return new BooleanFlagField(offset);
288 }
289
290 private final int offset;
291 private final int bitWidth;
292 private final E[] values;
293
294 private FlagField(int offset, E[] values) {
295 this.offset = offset;
296 this.bitWidth = bitWidth(values);
297 this.values = values;
298 }
299
300 @Nullable
301 public E get(int flags) {
302 int maskUnshifted = (1 << bitWidth) - 1;
303 int mask = maskUnshifted << offset;
304 int value = (flags & mask) >> offset;
305 for (E e : values) {
306 if (getIntValue(e) == value) {
307 return e;
308 }
309 }
310 return null;
311 }
312
313 public int toFlags(E value) {
314 return getIntValue(value) << offset;
315 }
316
317 protected abstract int getIntValue(E value);
318
319 }
320
321 public static class BooleanFlagField extends FlagField<Boolean> {
322 private static final Boolean[] BOOLEAN = { false, true };
323
324 public BooleanFlagField(int offset) {
325 super(offset, BOOLEAN);
326 }
327
328 @Override
329 protected int getIntValue(Boolean value) {
330 return value ? 1 : 0;
331 }
332
333 @NotNull
334 @Override
335 public Boolean get(int flags) {
336 //noinspection ConstantConditions
337 return super.get(flags);
338 }
339 }
340
341 private static class EnumLiteFlagField<E extends Internal.EnumLite> extends FlagField<E> {
342 public EnumLiteFlagField(int offset, E[] values) {
343 super(offset, values);
344 }
345
346 @Override
347 protected int getIntValue(E value) {
348 return value.getNumber();
349 }
350 }
351
352 }