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 }