/*
* Copyright (c) 2009, 2011, 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.
*
* 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.max.vm.tele;
import com.sun.max.annotate.*;
import com.sun.max.program.*;
import com.sun.max.vm.actor.member.*;
import com.sun.max.vm.compiler.target.*;
/**
* Makes critical state information about code remotely inspectable.
* <p>
* Active only when VM is being inspected.
*/
public final class InspectableCompilationInfo {
/**
* Maximum number of chars that may be written by the inspector into the char array, identifying classes requiring
* inspector notification upon method compilation.
*/
public static final int BREAKPOINT_DESCRIPTORS_ARRAY_LENGTH = 500;
/**
* Array into which the Inspector writes space-terminated type descriptors of all classes that currently require inspector
* notification upon method compilation.
* <br>
* Each time the Inspector writes into the array, it starts from the beginning and overwrites old data, and it writes into
* the {@linkplain #breakpointClassDescriptorsCharCount char count field} the number of characters written.
* <br>
* Each time the Inspector writes into the array, it increments the {@linkplain #breakpointClassDescriptorsEpoch generation counter}
* so that changes can be detected efficiently.
*
* @see #breakpointClassDescriptorsCharCount
* @see #breakpointClassDescriptorsEpoch
*/
@INSPECTED
private static char[] breakpointClassDescriptorCharArray = new char[BREAKPOINT_DESCRIPTORS_ARRAY_LENGTH];
/**
* Field into which the Inspector writes the count of characters written into the array of class descriptors each
* time that it does so.
*
* @see InspectableCompilationInfo#breakpointClassDescriptorCharArray
*/
@INSPECTED
private static int breakpointClassDescriptorsCharCount = 0;
/**
* Field into which the Inspector writes the number of times that it has written into the array of class descriptors each
* time that it does so.
*
* @see #breakpointClassDescriptorCharArray
*/
@INSPECTED
private static int breakpointClassDescriptorsEpoch = 0;
private static int lastRefreshedBreakpointClassDescriptorsEpoch = 0;
/**
* Type descriptors for all classes currently requiring inspector notification upon method compilation.
* These are reconstructed from the char array
* written by the Inspector each time the counter is noticed to have been incremented by the
* Inspector.
*
* @see #breakpointClassDescriptorsEpoch
* @see #breakpointClassDescriptorCharArray
*/
private static String[] breakpointClassDescriptors = new String[0];
/**
* Reads contents of the char array into which the Inspector may have written a sequence of class type descriptors, each
* terminated with a space character. Breaks these out into an array of strings, one type descriptor per element.
* <br>
* Only called when VM is being inspected.
*/
private static void refreshBreakpointClassDescriptors() {
if (breakpointClassDescriptorsCharCount < 0 || breakpointClassDescriptorsCharCount >= BREAKPOINT_DESCRIPTORS_ARRAY_LENGTH) {
throw ProgramError.unexpected("InspectableCodeInfo: bad char count from inspector=" + breakpointClassDescriptorsCharCount);
} else if (breakpointClassDescriptorsCharCount == 0) {
breakpointClassDescriptors = new String[0];
} else {
final String descriptorString = new String(breakpointClassDescriptorCharArray, 0, breakpointClassDescriptorsCharCount);
// System.out.println("BreakpointClassDescriptor string=\"" + descriptors + "\"");
breakpointClassDescriptors = descriptorString.split(" ");
// System.out.println("BreakpointClassDescriptors updated, count=" + breakpointClassDescriptors.length);
// for (String descriptor : breakpointClassDescriptors) {
// System.out.println(" \"" + descriptor + "\"");
// }
}
}
/**
* Makes information inspectable concerning a method compilation event.
* <br>
* <strong>Note:</strong> further optimization here is possible if it is determined that the string
* comparisons here (compare against every string in the list every time a method is compiled)
* take too long. It is hard to imagine improving unless a bottleneck is being created by
* having a very large number of classes listed with bytecode breakpoints.
*
* @param method method involved in compilation event
* @param targetMethod compilation just completed or {@code null} if this is a pre-compilation notification
*/
public static void notifyCompilationEvent(ClassMethodActor method, TargetMethod targetMethod) {
if (Inspectable.isVmInspected()) {
if (breakpointClassDescriptorsEpoch > lastRefreshedBreakpointClassDescriptorsEpoch) {
refreshBreakpointClassDescriptors();
lastRefreshedBreakpointClassDescriptorsEpoch = breakpointClassDescriptorsEpoch;
}
if (breakpointClassDescriptors.length > 0) {
final String typeDescriptorString = method.holder().typeDescriptor.string;
for (String breakpointClassTypeDescriptor : breakpointClassDescriptors) {
if (breakpointClassTypeDescriptor.equals(typeDescriptorString)) {
// Match: the method just compiled is in a class on the list of type descriptors written into the VM by the Inspector.
// Call the method that the Inspector is watching.
if (targetMethod == null) {
inspectableCompilationStarted(typeDescriptorString, method.name.string, method.descriptor.string);
} else {
inspectableCompilationCompleted(typeDescriptorString, method.name.string, method.descriptor.string, targetMethod);
}
break;
}
}
}
}
}
/**
* An empty method whose purpose is to be interrupted by the Inspector when it needs to monitor method compilation events
* in the VM. The arguments are deliberately made simple so that they can be read with low-level mechanisms in the
* Inspector. <br>
* <strong>Important:</strong> The Inspector assumes that this method is loaded and compiled in the boot image and
* that it will never be dynamically recompiled.
*
* @param holderType type description for class holding the method
* @param methodName name of the the method
* @param signature argument type descriptors for the method
*/
@NEVER_INLINE
@INSPECTED
private static void inspectableCompilationStarted(String holderType, String methodName, String signature) {
}
/**
* An empty method whose purpose is to be interrupted by the Inspector when it needs to monitor method compilation events
* in the VM. The arguments are deliberately made simple so that they can be read with low-level mechanisms in the
* Inspector. <br>
* <strong>Important:</strong> The Inspector assumes that this method is loaded and compiled in the boot image and
* that it will never be dynamically recompiled.
*
* @param holderType type description for class holding the method
* @param methodName name of the the method
* @param signature argument type descriptors for the method
* @param targetMethod the result of the method compilation
*/
@NEVER_INLINE
@INSPECTED
private static void inspectableCompilationCompleted(String holderType, String methodName, String signature, TargetMethod targetMethod) {
}
}