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 }