--- /dev/null 2017-11-09 09:38:01.297999907 +0100 +++ new/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java 2018-04-09 16:05:58.344226027 +0200 @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2016, 2018, 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.jfr.internal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import jdk.jfr.AnnotationElement; +import jdk.jfr.Event; +import jdk.jfr.SettingControl; +import jdk.jfr.ValueDescriptor; + +/** + * Internal data structure that describes a type, + * + * Used to create event types, value descriptor and annotations. + * + */ +public class Type implements Comparable { + public static final String SUPER_TYPE_ANNOTATION = java.lang.annotation.Annotation.class.getName(); + public static final String SUPER_TYPE_SETTING = SettingControl.class.getName(); + public static final String SUPER_TYPE_EVENT = Event.class.getName(); + public static final String ORACLE_EVENT_PREFIX = "com.oracle.jdk."; + public static final String ORACLE_TYPE_PREFIX = "com.oracle.jfr.types."; + + // Initialization of known types + private final static Map> knownTypes = new HashMap<>(); + static final Type BOOLEAN = register(boolean.class, new Type("boolean", null, 4)); + static final Type CHAR = register(char.class, new Type("char", null, 5)); + static final Type FLOAT = register(float.class, new Type("float", null, 6)); + static final Type DOUBLE = register(double.class, new Type("double", null, 7)); + static final Type BYTE = register(byte.class, new Type("byte", null, 8)); + static final Type SHORT = register(short.class, new Type("short", null, 9)); + static final Type INT = register(int.class, new Type("int", null, 10)); + static final Type LONG = register(long.class, new Type("long", null, 11)); + static final Type CLASS = register(Class.class, new Type("java.lang.Class", null, 20)); + static final Type STRING = register(String.class, new Type("java.lang.String", null, 21)); + static final Type THREAD = register(Thread.class, new Type("java.lang.Thread", null, 22)); + static final Type STACK_TRACE = register(null, new Type(ORACLE_TYPE_PREFIX + "StackTrace", null, 23)); + + private final AnnotationConstruct annos = new AnnotationConstruct(); + private final String name; + private final String superType; + private final boolean constantPool; + private final long id; + private final ArrayList fields = new ArrayList<>(); + private Boolean simpleType; // calculated lazy + private boolean remove = true; + /** + * Creates a type + * + * @param javaTypeName i.e "com.oracle.jfr.type.StackFrame" + * @param superType i.e "com.oracle.jfr.Event" and "java.lang.Annotation" + * @param id the class id that represents the class in the JVM + * + */ + public Type(String javaTypeName, String superType, long typeId) { + this(javaTypeName, superType, typeId, false); + } + + Type(String javaTypeName, String superType, long typeId, boolean contantPool) { + this(javaTypeName, superType, typeId, contantPool, null); + } + + Type(String javaTypeName, String superType, long typeId, boolean contantPool, Boolean simpleType) { + Objects.requireNonNull(javaTypeName); + + if (!isValidJavaIdentifier(javaTypeName)) { + throw new IllegalArgumentException(javaTypeName + " is not a valid Java identifier"); + } + this.constantPool = contantPool; + this.superType = superType; + this.name = javaTypeName; + this.id = typeId; + this.simpleType = simpleType; + } + + static boolean isDefinedByJVM(long id) { + return id < JVM.RESERVED_CLASS_ID_LIMIT; + } + + public static long getTypeId(Class clazz) { + Type type = Type.getKnownType(clazz); + return type == null ? JVM.getJVM().getTypeId(clazz) : type.getId(); + } + + static Collection getKnownTypes() { + return knownTypes.keySet(); + } + + public static boolean isValidJavaIdentifier(String identifier) { + if (identifier.isEmpty()) { + return false; + } + if (!Character.isJavaIdentifierStart(identifier.charAt(0))) { + return false; + } + for (int i = 1; i < identifier.length(); i++) { + char c = identifier.charAt(i); + if (c != '.') { + if (!Character.isJavaIdentifierPart(c)) { + return false; + } + } + } + return true; + } + + public static boolean isValidJavaFieldType(String name) { + for (Map.Entry> entry : knownTypes.entrySet()) { + Class clazz = entry.getValue(); + if (clazz != null && name.equals(clazz.getName())) { + return true; + } + } + return false; + } + + public static Class getKnownType(String className) { + for (Map.Entry> entry : knownTypes.entrySet()) { + Class clazz = entry.getValue(); + if (clazz != null) { + String knownClassName = clazz.getName(); + if (className.equals(knownClassName)) { + return clazz; + } + } + } + return null; + } + + static boolean isKnownType(Class type) { + if (type.isPrimitive()) { + return true; + } + if (type.equals(Class.class) || type.equals(Thread.class) || type.equals(String.class)) { + return true; + } + return false; + } + + public static Type getKnownType(Class clazz) { + for (Map.Entry> entry : knownTypes.entrySet()) { + if (clazz != null && clazz.equals(entry.getValue())) { + return entry.getKey(); + } + } + return null; + } + + public String getName() { + return name; + } + + public String getLogName() { + return getName() + "(" + getId() + ")"; + } + + public List getFields() { + return fields; + } + + public boolean isSimpleType() { + if (simpleType == null) { + simpleType = calculateSimpleType(); + } + return simpleType.booleanValue(); + } + + private boolean calculateSimpleType() { + if (fields.size() != 1) { + return false; + } + // annotation, settings and event can never be simple types + return superType == null; + } + + public boolean isDefinedByJVM() { + return id < JVM.RESERVED_CLASS_ID_LIMIT; + } + + private static Type register(Class clazz, Type type) { + knownTypes.put(type, clazz); + return type; + } + + public void add(ValueDescriptor valueDescriptor) { + Objects.requireNonNull(valueDescriptor); + fields.add(valueDescriptor); + } + + void trimFields() { + fields.trimToSize(); + } + + void setAnnotations(List annotations) { + annos.setAnnotationElements(annotations); + } + + public String getSuperType() { + return superType; + } + + public long getId() { + return id; + } + + public boolean isConstantPool() { + return constantPool; + } + + public String getLabel() { + return annos.getLabel(); + } + + public List getAnnotationElements() { + return annos.getUnmodifiableAnnotationElements(); + } + + public T getAnnotation(Class clazz) { + return annos.getAnnotation(clazz); + } + + public String getDescription() { + return annos.getDescription(); + } + + @Override + public int hashCode() { + return Long.hashCode(id); + } + + @Override + public boolean equals(Object object) { + if (object instanceof Type) { + Type that = (Type) object; + return that.id == this.id; + } + return false; + } + + @Override + public int compareTo(Type that) { + return Long.compare(this.id, that.id); + } + + void log(String action, LogTag logTag, LogLevel level) { + if (logTag.shouldLog(level.level) && !isSimpleType()) { + Logger.log(logTag, LogLevel.TRACE, action + " " + typeText() + " " + getLogName() + " {"); + for (ValueDescriptor v : getFields()) { + String array = v.isArray() ? "[]" : ""; + Logger.log(logTag, LogLevel.TRACE, " " + v.getTypeName() + array + " " + v.getName() + ";"); + } + Logger.log(logTag, LogLevel.TRACE, "}"); + } else { + if (logTag.shouldLog(LogLevel.INFO.level) && !isSimpleType()) { + Logger.log(logTag, LogLevel.INFO, action + " " + typeText() + " " + getLogName()); + } + } + } + + private String typeText() { + if (this instanceof PlatformEventType) { + return "event type"; + } + if (Type.SUPER_TYPE_SETTING.equals(superType)) { + return "setting type"; + } + if (Type.SUPER_TYPE_ANNOTATION.equals(superType)) { + return "annotation type"; + } + return "type"; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getLogName()); + if (!getFields().isEmpty()) { + sb.append(" {\n"); + for (ValueDescriptor td : getFields()) { + sb.append(" type=" + td.getTypeName() + "(" + td.getTypeId() + ") name=" + td.getName() + "\n"); + } + sb.append("}\n"); + } + return sb.toString(); + } + + public void setRemove(boolean remove) { + this.remove = remove; + } + + public boolean getRemove() { + return remove; + } +}