All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.malamut2.low.StaticClassWriter Maven / Gradle / Ivy

Go to download

A Java agent which traces creation of all objects whose net size cross a given threshold.

There is a newer version: 1.0.3
Show newest version
/***
 * ASM tests
 * Copyright (c) 2002-2005 France Telecom
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holders nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

// Portions Copyright 2011 Google, Inc.
//
// This is an extracted version of the ClassInfo and ClassWriter
// portions of ClassWriterComputeFramesTest in the set of ASM tests.
// We have done a fair bit of rewriting for readability, and changed
// the comments.  The original author is Eric Bruneton.


package com.github.malamut2.low;

import java.io.IOException;
import java.io.InputStream;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

/**
 * A {@link ClassWriter} that looks for static class data in the
 * classpath when the classes are not available at runtime.
 *
 * 

ClassWriter uses class hierarchy information, which it gets by * looking at loaded classes, to make some decisions about the best * way to write classes. The problem with this is that it fails if * the superclass hasn't been loaded yet. StaticClassWriter fails * over to looking for the class hierarchy information in the * ClassLoader's resources (usually the classpath) if the class it * needs hasn't been loaded yet. * *

This class was heavily influenced by ASM's * org.objectweb.asm.util.ClassWriterComputeFramesTest, which contains * the same logic in a subclass. The code here has been slightly * cleaned up for readability. * * @author [email protected] (Jeremy Manson) */ class StaticClassWriter extends ClassWriter { /* The classloader that we use to look for the unloaded class */ private final ClassLoader classLoader; /** * {@inheritDoc} * @param classLoader the class loader that loaded this class */ public StaticClassWriter( ClassReader classReader, int flags, ClassLoader classLoader) { super(classReader, flags); this.classLoader = classLoader; } /** * {@inheritDoc} */ @Override protected String getCommonSuperClass( final String type1, final String type2) { try { return super.getCommonSuperClass(type1, type2); } catch (Throwable e) { // Try something else... } // Exactly the same as in ClassWriter, but gets the superclass // directly from the class file. ClassInfo ci1, ci2; try { ci1 = new ClassInfo(type1, classLoader); ci2 = new ClassInfo(type2, classLoader); } catch (Throwable e) { throw new RuntimeException(e); } if (ci1.isAssignableFrom(ci2)) { return type1; } if (ci2.isAssignableFrom(ci1)) { return type2; } if (ci1.isInterface() || ci2.isInterface()) { return "java/lang/Object"; } do { // Should never be null, because if ci1 were the Object class // or an interface, it would have been caught above. ci1 = ci1.getSuperclass(); } while (!ci1.isAssignableFrom(ci2)); return ci1.getType().getInternalName(); } /** * For a given class, this stores the information needed by the * getCommonSuperClass test. This determines if the class is * available at runtime, and then, if it isn't, it tries to get the * class file, and extract the appropriate information from that. */ static class ClassInfo { private final Type type; private final ClassLoader loader; private final boolean isInterface; private final String superClass; private final String[] interfaces; public ClassInfo(String type, ClassLoader loader) { Class cls = null; // First, see if we can extract the information from the class... try { cls = Class.forName(type); } catch (Exception e) { // failover... } if (cls != null) { this.type = Type.getType(cls); this.loader = loader; this.isInterface = cls.isInterface(); this.superClass = cls.getSuperclass().getName(); Class[] ifs = cls.getInterfaces(); this.interfaces = new String[ifs.length]; for (int i = 0; i < ifs.length; i++) { this.interfaces[i] = ifs[i].getName(); } return; } // The class isn't loaded. Try to get the class file, and // extract the information from that. this.loader = loader; this.type = Type.getObjectType(type); String fileName = type.replace('.', '/') + ".class"; InputStream is = null; ClassReader cr; try { is = (loader == null) ? ClassLoader.getSystemResourceAsStream(fileName) : loader.getResourceAsStream(fileName); cr = new ClassReader(is); } catch (IOException e) { throw new RuntimeException(e); } finally { if (is != null) { try { is.close(); } catch (Exception e) { // don't worry if closing an input stream fails } } } int offset = cr.header; isInterface = (cr.readUnsignedShort(offset) & Opcodes.ACC_INTERFACE) != 0; char[] buf = new char[2048]; // Read the superclass offset += 4; superClass = readConstantPoolString(cr, offset, buf); // Read the interfaces offset += 2; int numInterfaces = cr.readUnsignedShort(offset); interfaces = new String[numInterfaces]; offset += 2; for (int i = 0; i < numInterfaces; i++) { interfaces[i] = readConstantPoolString(cr, offset, buf); offset += 2; } } String readConstantPoolString(ClassReader cr, int offset, char[] buf) { int cpIndex = cr.getItem(cr.readUnsignedShort(offset)); if (cpIndex == 0) { return null; // throw new RuntimeException("Bad constant pool index"); } return cr.readUTF8(cpIndex, buf); } Type getType() { return type; } ClassInfo getSuperclass() { if (superClass == null) { return null; } return new ClassInfo(superClass, loader); } /** * Same as {@link Class#getInterfaces()} */ ClassInfo[] getInterfaces() { if (interfaces == null) { return new ClassInfo[0]; } ClassInfo[] result = new ClassInfo[interfaces.length]; for (int i = 0; i < result.length; ++i) { result[i] = new ClassInfo(interfaces[i], loader); } return result; } /** * Same as {@link Class#isInterface} */ boolean isInterface() { return isInterface; } private boolean implementsInterface(ClassInfo that) { for (ClassInfo c = this; c != null; c = c.getSuperclass()) { for (ClassInfo iface : c.getInterfaces()) { if (iface.type.equals(that.type) || iface.implementsInterface(that)) { return true; } } } return false; } private boolean isSubclassOf(ClassInfo that) { for (ClassInfo ci = this; ci != null; ci = ci.getSuperclass()) { if (ci.getSuperclass() != null && ci.getSuperclass().type.equals(that.type)) { return true; } } return false; } /** * Same as {@link Class#isAssignableFrom(Class)} */ boolean isAssignableFrom(ClassInfo that) { return (this == that || that.isSubclassOf(this) || that.implementsInterface(this) || (that.isInterface() && getType().getDescriptor().equals("Ljava/lang/Object;"))); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy