/*
* Copyright (c) 2008, 2016, 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 com.sun.btrace.runtime;
import com.sun.btrace.org.objectweb.asm.ClassReader;
import com.sun.btrace.org.objectweb.asm.ClassVisitor;
import com.sun.btrace.org.objectweb.asm.ClassWriter;
import static com.sun.btrace.org.objectweb.asm.Opcodes.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashSet;
import java.util.Set;
import static com.sun.btrace.runtime.Constants.OBJECT_INTERNAL;
/**
* @author A. Sundararajan
* @author J. Bachorik
*/
public final class InstrumentUtils {
/**
* Collects the type hierarchy into the provided list, sorted from the actual type to root.
* Common superclasses may be present multiple times (eg. {@code java.lang.Object})
* It will use the associated classloader to locate the class file resources.
* @param cl the associated classloader
* @param type the type to compute the hierarchy closure for (either Java or internal name format)
* @param closure the ordered set to store the closure in
* @param useInternal should internal types names be used in the closure
*/
public static void collectHierarchyClosure(ClassLoader cl, String type,
Set<String> closure, boolean useInternal) {
if (type == null || type.equals(OBJECT_INTERNAL)) {
return;
}
ClassInfo ci = ClassCache.getInstance().get(cl, type);
Set<ClassInfo> ciSet = new LinkedHashSet<>();
// add self
ciSet.add(ci);
for(ClassInfo sci : ci.getSupertypes(false)) {
if (!sci.isInterface() && !sci.getClassName().equals(OBJECT_INTERNAL)) {
ciSet.add(sci);
}
}
for (ClassInfo sci : ciSet) {
closure.add(useInternal ? sci.getClassName() : sci.getJavaClassName());
}
}
public static String arrayDescriptorFor(int typeCode) {
switch (typeCode) {
case T_BOOLEAN:
return "[Z";
case T_CHAR:
return "[C";
case T_FLOAT:
return "[F";
case T_DOUBLE:
return "[D";
case T_BYTE:
return "[B";
case T_SHORT:
return "[S";
case T_INT:
return "[I";
case T_LONG:
return "[J";
default:
throw new IllegalArgumentException();
}
}
public static void accept(ClassReader reader, ClassVisitor visitor) {
accept(reader, visitor, ClassReader.SKIP_FRAMES);
}
public static void accept(ClassReader reader, ClassVisitor visitor, int flags) {
if (reader == null || visitor == null) return;
reader.accept(visitor, flags);
}
private static boolean isJDK16OrAbove(byte[] code) {
return isJDK16OrAbove(getMajor(code));
}
private static boolean isJDK16OrAbove(BTraceClassReader cr) {
return isJDK16OrAbove(getMajor(cr));
}
private static boolean isJDK16OrAbove(int major) {
return major >= 50;
}
private static int getMajor(BTraceClassReader cr) {
return cr.getClassVersion();
}
private static int getMajor(byte[] code) {
// skip 0xCAFEBABE magic and minor version
final int majorOffset = 4 + 2;
return (((code[majorOffset] << 8) & 0xFF00) |
((code[majorOffset + 1]) & 0xFF));
}
public static ClassWriter newClassWriter() {
return newClassWriter(null, ClassWriter.COMPUTE_FRAMES);
}
static BTraceClassWriter newClassWriter(ClassLoader cl, byte[] code) {
int flags = ClassWriter.COMPUTE_MAXS;
if (isJDK16OrAbove(code)) {
flags = ClassWriter.COMPUTE_FRAMES;
}
return newClassWriter(new BTraceClassReader(cl, code), flags);
}
static BTraceClassWriter newClassWriter(BTraceClassReader cr) {
int flags = ClassWriter.COMPUTE_MAXS;
if (isJDK16OrAbove(cr)) {
flags = ClassWriter.COMPUTE_FRAMES;
}
return newClassWriter(cr, flags);
}
static BTraceClassWriter newClassWriter(BTraceClassReader reader, int flags) {
BTraceClassWriter cw = null;
cw = reader != null ? new BTraceClassWriter(reader.getClassLoader(), reader, flags) :
new BTraceClassWriter(null, flags);
return cw;
}
static BTraceClassReader newClassReader(byte[] code) {
return new BTraceClassReader(ClassLoader.getSystemClassLoader(), code);
}
static BTraceClassReader newClassReader(ClassLoader cl, byte[] code) {
return new BTraceClassReader(cl, code);
}
static BTraceClassReader newClassReader(InputStream is)
throws IOException{
return new BTraceClassReader(ClassLoader.getSystemClassLoader(), is);
}
static BTraceClassReader newClassReader(ClassLoader cl, InputStream is)
throws IOException{
return new BTraceClassReader(cl, is);
}
static final String getActionPrefix(String className) {
return Constants.BTRACE_METHOD_PREFIX + className.replace('/', '$') + "$";
}
}