/* * Copyright (c) 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.ClassVisitor; import com.sun.btrace.org.objectweb.asm.ClassWriter; import java.util.Deque; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; /** * A hacked version of <a href="http://asm.ow2.org/asm50/javadoc/user/org/objectweb/asm/ClassWriter.html">ClassWriter</a> * allowing to plug-in instrumentation providers and instrument class in single invocation. Also, it provides * a smart and lightweight common supertype resolution method for computing frames. * @author Jaroslav Bachorik */ final class BTraceClassWriter extends ClassWriter { private final Deque<Instrumentor> instrumentors = new LinkedList<>(); private final ClassLoader targetCL; private final BTraceClassReader cr; BTraceClassWriter(ClassLoader cl, int flags) { super(flags); this.targetCL = cl != null ? cl : ClassLoader.getSystemClassLoader(); this.cr = null; } BTraceClassWriter(ClassLoader cl, BTraceClassReader reader, int flags) { super(reader, flags); this.targetCL = cl != null ? cl : ClassLoader.getSystemClassLoader(); this.cr = reader; } public void addInstrumentor(BTraceProbe bp) { if (cr != null && bp != null) { synchronized(instrumentors) { Instrumentor top = instrumentors.peekLast(); ClassVisitor parent = top != null ? top : this; Instrumentor i = Instrumentor.create(cr, bp, parent); if (i != null) { instrumentors.add(i); } } } } public byte[] instrument() { boolean hit = false; synchronized(instrumentors) { if (instrumentors.isEmpty()) return null; ClassVisitor top = instrumentors.peekLast(); InstrumentUtils.accept(cr, top != null ? top : this); for(Instrumentor i : instrumentors) { hit |= i.hasMatch(); } } return hit ? this.toByteArray() : null; } @Override protected String getCommonSuperClass(String type1, String type2) { // Using type closures resolved via the associate classloader LinkedHashSet<String> type1Closure = new LinkedHashSet<>(); LinkedHashSet<String> type2Closure = new LinkedHashSet<>(); InstrumentUtils.collectHierarchyClosure(targetCL, type1, type1Closure, true); InstrumentUtils.collectHierarchyClosure(targetCL, type2, type2Closure, true); // basically, do intersection type1Closure.retainAll(type2Closure); // if the intersection is not empty the first element is the closest common ancestor Iterator<String> iter = type1Closure.iterator(); if (iter.hasNext()) { String common = iter.next(); return common; } return Constants.OBJECT_INTERNAL; } }