/
niceSOFT
/
openjdk21
Обзор
Документация
Войти
/
niceSOFT
/
openjdk21
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java
282 строки
14 KB
Adam Sotona
8294982: Implementation of Classfile API
09 мар 2023, 18:23
09 мар 2023, 18:23
4655b79
Код
Авторство
О чём код?
/* * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package jdk.internal.classfile.impl; import jdk.internal.classfile.Annotation; import jdk.internal.classfile.AnnotationElement; import jdk.internal.classfile.AnnotationValue; import jdk.internal.classfile.ClassReader; import jdk.internal.classfile.constantpool.*; import jdk.internal.classfile.TypeAnnotation; import static jdk.internal.classfile.Classfile.*; import static jdk.internal.classfile.TypeAnnotation.TargetInfo.*; import java.util.List; import jdk.internal.classfile.Label; import jdk.internal.classfile.constantpool.Utf8Entry; import jdk.internal.access.SharedSecrets; class AnnotationReader { private AnnotationReader() { } public static List<Annotation> readAnnotations(ClassReader classReader, int p) { int pos = p; int numAnnotations = classReader.readU2(pos); var annos = new Object[numAnnotations]; pos += 2; for (int i = 0; i < numAnnotations; ++i) { annos[i] = readAnnotation(classReader, pos); pos = skipAnnotation(classReader, pos); } return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(annos); } public static AnnotationValue readElementValue(ClassReader classReader, int p) { char tag = (char) classReader.readU1(p); ++p; return switch (tag) { case 'B' -> new AnnotationImpl.OfByteImpl((IntegerEntry)classReader.readEntry(p)); case 'C' -> new AnnotationImpl.OfCharacterImpl((IntegerEntry)classReader.readEntry(p)); case 'D' -> new AnnotationImpl.OfDoubleImpl((DoubleEntry)classReader.readEntry(p)); case 'F' -> new AnnotationImpl.OfFloatImpl((FloatEntry)classReader.readEntry(p)); case 'I' -> new AnnotationImpl.OfIntegerImpl((IntegerEntry)classReader.readEntry(p)); case 'J' -> new AnnotationImpl.OfLongImpl((LongEntry)classReader.readEntry(p)); case 'S' -> new AnnotationImpl.OfShortImpl((IntegerEntry)classReader.readEntry(p)); case 'Z' -> new AnnotationImpl.OfBooleanImpl((IntegerEntry)classReader.readEntry(p)); case 's' -> new AnnotationImpl.OfStringImpl(classReader.readUtf8Entry(p)); case 'e' -> new AnnotationImpl.OfEnumImpl(classReader.readUtf8Entry(p), classReader.readUtf8Entry(p + 2)); case 'c' -> new AnnotationImpl.OfClassImpl(classReader.readUtf8Entry(p)); case '@' -> new AnnotationImpl.OfAnnotationImpl(readAnnotation(classReader, p)); case '[' -> { int numValues = classReader.readU2(p); p += 2; var values = new Object[numValues]; for (int i = 0; i < numValues; ++i) { values[i] = readElementValue(classReader, p); p = skipElementValue(classReader, p); } yield new AnnotationImpl.OfArrayImpl(SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(values)); } default -> throw new IllegalArgumentException( "Unexpected tag '%s' in AnnotationValue, pos = %d".formatted(tag, p - 1)); }; } public static List<TypeAnnotation> readTypeAnnotations(ClassReader classReader, int p, LabelContext lc) { int numTypeAnnotations = classReader.readU2(p); p += 2; var annotations = new Object[numTypeAnnotations]; for (int i = 0; i < numTypeAnnotations; ++i) { annotations[i] = readTypeAnnotation(classReader, p, lc); p = skipTypeAnnotation(classReader, p); } return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(annotations); } public static List<List<Annotation>> readParameterAnnotations(ClassReader classReader, int p) { int cnt = classReader.readU1(p++); var pas = new Object[cnt]; for (int i = 0; i < cnt; ++i) { pas[i] = readAnnotations(classReader, p); p = skipAnnotations(classReader, p); } return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(pas); } private static int skipElementValue(ClassReader classReader, int p) { char tag = (char) classReader.readU1(p); ++p; return switch (tag) { case 'B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z', 's', 'c' -> p + 2; case 'e' -> p + 4; case '@' -> skipAnnotation(classReader, p); case '[' -> { int numValues = classReader.readU2(p); p += 2; for (int i = 0; i < numValues; ++i) { p = skipElementValue(classReader, p); } yield p; } default -> throw new IllegalArgumentException( "Unexpected tag '%s' in AnnotationValue, pos = %d".formatted(tag, p - 1)); }; } private static Annotation readAnnotation(ClassReader classReader, int p) { Utf8Entry annotationClass = classReader.utf8EntryByIndex(classReader.readU2(p)); p += 2; List<AnnotationElement> elems = readAnnotationElementValuePairs(classReader, p); return new AnnotationImpl(annotationClass, elems); } private static int skipAnnotations(ClassReader classReader, int p) { int numAnnotations = classReader.readU2(p); p += 2; for (int i = 0; i < numAnnotations; ++i) p = skipAnnotation(classReader, p); return p; } private static int skipAnnotation(ClassReader classReader, int p) { return skipElementValuePairs(classReader, p + 2); } private static List<AnnotationElement> readAnnotationElementValuePairs(ClassReader classReader, int p) { int numElementValuePairs = classReader.readU2(p); p += 2; var annotationElements = new Object[numElementValuePairs]; for (int i = 0; i < numElementValuePairs; ++i) { Utf8Entry elementName = classReader.readUtf8Entry(p); p += 2; AnnotationValue value = readElementValue(classReader, p); annotationElements[i] = new AnnotationImpl.AnnotationElementImpl(elementName, value); p = skipElementValue(classReader, p); } return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(annotationElements); } private static int skipElementValuePairs(ClassReader classReader, int p) { int numElementValuePairs = classReader.readU2(p); p += 2; for (int i = 0; i < numElementValuePairs; ++i) { p = skipElementValue(classReader, p + 2); } return p; } private static Label getLabel(LabelContext lc, int bciOffset, int targetType, int p) { //helper method to avoid NPE if (lc == null) throw new IllegalArgumentException("Unexpected targetType '%d' in TypeAnnotation outside of Code attribute, pos = %d".formatted(targetType, p - 1)); return lc.getLabel(bciOffset); } private static TypeAnnotation readTypeAnnotation(ClassReader classReader, int p, LabelContext lc) { int targetType = classReader.readU1(p++); var targetInfo = switch (targetType) { case TAT_CLASS_TYPE_PARAMETER -> ofClassTypeParameter(classReader.readU1(p)); case TAT_METHOD_TYPE_PARAMETER -> ofMethodTypeParameter(classReader.readU1(p)); case TAT_CLASS_EXTENDS -> ofClassExtends(classReader.readU2(p)); case TAT_CLASS_TYPE_PARAMETER_BOUND -> ofClassTypeParameterBound(classReader.readU1(p), classReader.readU1(p + 1)); case TAT_METHOD_TYPE_PARAMETER_BOUND -> ofMethodTypeParameterBound(classReader.readU1(p), classReader.readU1(p + 1)); case TAT_FIELD -> ofField(); case TAT_METHOD_RETURN -> ofMethodReturn(); case TAT_METHOD_RECEIVER -> ofMethodReceiver(); case TAT_METHOD_FORMAL_PARAMETER -> ofMethodFormalParameter(classReader.readU1(p)); case TAT_THROWS -> ofThrows(classReader.readU2(p)); case TAT_LOCAL_VARIABLE -> ofLocalVariable(readLocalVarEntries(classReader, p, lc, targetType)); case TAT_RESOURCE_VARIABLE -> ofResourceVariable(readLocalVarEntries(classReader, p, lc, targetType)); case TAT_EXCEPTION_PARAMETER -> ofExceptionParameter(classReader.readU2(p)); case TAT_INSTANCEOF -> ofInstanceofExpr(getLabel(lc, classReader.readU2(p), targetType, p)); case TAT_NEW -> ofNewExpr(getLabel(lc, classReader.readU2(p), targetType, p)); case TAT_CONSTRUCTOR_REFERENCE -> ofConstructorReference(getLabel(lc, classReader.readU2(p), targetType, p)); case TAT_METHOD_REFERENCE -> ofMethodReference(getLabel(lc, classReader.readU2(p), targetType, p)); case TAT_CAST -> ofCastExpr(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); case TAT_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -> ofConstructorInvocationTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); case TAT_METHOD_INVOCATION_TYPE_ARGUMENT -> ofMethodInvocationTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); case TAT_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -> ofConstructorReferenceTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); case TAT_METHOD_REFERENCE_TYPE_ARGUMENT -> ofMethodReferenceTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); default -> throw new IllegalArgumentException("Unexpected targetType '%d' in TypeAnnotation, pos = %d".formatted(targetType, p - 1)); }; p += targetInfo.size(); int pathLength = classReader.readU1(p++); TypeAnnotation.TypePathComponent[] typePath = new TypeAnnotation.TypePathComponent[pathLength]; for (int i = 0; i < pathLength; ++i) { int typePathKindTag = classReader.readU1(p++); int typeArgumentIndex = classReader.readU1(p++); typePath[i] = switch (typePathKindTag) { case 0 -> TypeAnnotation.TypePathComponent.ARRAY; case 1 -> TypeAnnotation.TypePathComponent.INNER_TYPE; case 2 -> TypeAnnotation.TypePathComponent.WILDCARD; case 3 -> new UnboundAttribute.TypePathComponentImpl(TypeAnnotation.TypePathComponent.Kind.TYPE_ARGUMENT, typeArgumentIndex); default -> throw new IllegalArgumentException("Unknown type annotation path component kind: " + typePathKindTag); }; } // the annotation info for this annotation Utf8Entry type = classReader.readUtf8Entry(p); p += 2; return TypeAnnotation.of(targetInfo, List.of(typePath), type, readAnnotationElementValuePairs(classReader, p)); } private static List<TypeAnnotation.LocalVarTargetInfo> readLocalVarEntries(ClassReader classReader, int p, LabelContext lc, int targetType) { int tableLength = classReader.readU2(p); p += 2; var entries = new Object[tableLength]; for (int i = 0; i < tableLength; ++i) { int startPc = classReader.readU2(p); entries[i] = TypeAnnotation.LocalVarTargetInfo.of( getLabel(lc, startPc, targetType, p), getLabel(lc, startPc + classReader.readU2(p + 2), targetType, p - 2), classReader.readU2(p + 4)); p += 6; } return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(entries); } private static int skipTypeAnnotation(ClassReader classReader, int p) { int targetType = classReader.readU1(p++); p += switch (targetType) { case 0x13, 0x14, 0x15 -> 0; case 0x00, 0x01, 0x16 -> 1; case 0x10, 0x11, 0x12, 0x17, 0x42, 0x43, 0x44, 0x45, 0x46 -> 2; case 0x47, 0x48, 0x49, 0x4A, 0x4B -> 3; case 0x40, 0x41 -> 2 + classReader.readU2(p) * 6; default -> throw new IllegalArgumentException( "Unexpected targetType '%d' in TypeAnnotation, pos = %d".formatted(targetType, p - 1)); }; int pathLength = classReader.readU1(p++); p += pathLength * 2; // the annotation info for this annotation p += 2; p = skipElementValuePairs(classReader, p); return p; } }