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 }