/*
* Copyright (c) 2012, 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.ext.jvmti;
import static com.sun.max.vm.ext.jvmti.JVMTIConstants.*;
import static com.sun.max.vm.ext.jvmti.JVMTIEnvNativeStruct.*;
import java.util.*;
import com.sun.max.unsafe.*;
import com.sun.max.vm.actor.holder.*;
import com.sun.max.vm.ext.jvmti.JJVMTI.*;
/**
* JVMTI Capabilities.
* A capability is on if the relevant bit is set in the {@code jvmtiCapabilities struct} is set.
* TODO This code currently assume 64 bit,little endian architecture.
* We have enabled some unimplemented capabilities for jdwp evaluation
*/
public class JVMTICapabilities {
public enum E {
CAN_TAG_OBJECTS(true),
CAN_GENERATE_FIELD_MODIFICATION_EVENTS(true),
CAN_GENERATE_FIELD_ACCESS_EVENTS(true),
CAN_GET_BYTECODES(true),
CAN_GET_SYNTHETIC_ATTRIBUTE(true),
CAN_GET_OWNED_MONITOR_INFO(false),
CAN_GET_CURRENT_CONTENDED_MONITOR(false),
CAN_GET_MONITOR_INFO(false),
CAN_POP_FRAME(false),
CAN_REDEFINE_CLASSES(false),
CAN_SIGNAL_THREAD(true),
CAN_GET_SOURCE_FILE_NAME(true),
CAN_GET_LINE_NUMBERS(true),
CAN_GET_SOURCE_DEBUG_EXTENSION(true),
CAN_ACCESS_LOCAL_VARIABLES(true),
CAN_MAINTAIN_ORIGINAL_METHOD_ORDER(true),
CAN_GENERATE_SINGLE_STEP_EVENTS(true),
CAN_GENERATE_EXCEPTION_EVENTS(true),
CAN_GENERATE_FRAME_POP_EVENTS(true),
CAN_GENERATE_BREAKPOINT_EVENTS(true),
CAN_SUSPEND(true),
CAN_REDEFINE_ANY_CLASS(false),
CAN_GET_CURRENT_THREAD_CPU_TIME(false),
CAN_GET_THREAD_CPU_TIME(false),
CAN_GENERATE_METHOD_ENTRY_EVENTS(true),
CAN_GENERATE_METHOD_EXIT_EVENTS(true),
CAN_GENERATE_ALL_CLASS_HOOK_EVENTS(true),
CAN_GENERATE_COMPILED_METHOD_LOAD_EVENTS(true),
CAN_GENERATE_MONITOR_EVENTS(true), // TODO
CAN_GENERATE_VM_OBJECT_ALLOC_EVENTS(false),
CAN_GENERATE_NATIVE_METHOD_BIND_EVENTS(false),
CAN_GENERATE_GARBAGE_COLLECTION_EVENTS(true),
CAN_GENERATE_OBJECT_FREE_EVENTS(false),
CAN_FORCE_EARLY_RETURN(false),
CAN_GET_OWNED_MONITOR_STACK_DEPTH_INFO(false),
CAN_GET_CONSTANT_POOL(false),
CAN_SET_NATIVE_METHOD_PREFIX(false),
CAN_RETRANSFORM_CLASSES(false),
CAN_RETRANSFORM_ANY_CLASS(false),
CAN_GENERATE_RESOURCE_EXHAUSTION_HEAP_EVENTS(false),
CAN_GENERATE_RESOURCE_EXHAUSTION_THREADS_EVENTS(false);
/**
* {code true} iff the VM can (ever) implement this capability.
*/
final boolean can;
/**
* Value with relevant bit for this capability set.
*/
final long bitMask;
/**
* Value with all possible implementable capabilities.
*/
static long allMask;
static EnumSet<E> allEnumSet = EnumSet.noneOf(E.class);
static final E[] VALUES = values();
static {
for (int i = 0; i < VALUES.length; i++) {
E cap = VALUES[i];
if (cap.can) {
allMask |= cap.bitMask;
allEnumSet.add(cap);
}
}
}
E(boolean t) {
can = t;
bitMask = 1L << ordinal();
}
/**
* Gets the value of the capability in the given C struct denoted by {@code base}.
*
* @param base pointer to a {@code jvmtiCapabilities struct}
* @return {@code true} if this capability is set, {@code false} otherwise
*/
boolean get(Pointer base) {
return (base.readLong(0) & bitMask) != 0;
}
void set(Pointer base, boolean value) {
long oldValue = base.readLong(0);
if (value) {
oldValue = oldValue | bitMask;
} else {
oldValue = oldValue & ~bitMask;
}
base.setLong(0, oldValue);
}
static void setAll(Pointer base) {
base.setLong(0, allMask);
}
}
static int addCapabilities(Pointer env, Pointer capabilitiesPtr) {
Pointer envCaps = CAPABILITIES.getPtr(env);
for (int i = 0; i < E.VALUES.length; i++) {
E cap = E.VALUES[i];
if (cap.get(capabilitiesPtr)) {
if (cap.can) {
cap.set(envCaps, true);
if (cap == E.CAN_MAINTAIN_ORIGINAL_METHOD_ORDER) {
ClassActor.preserveMethodActorOrder();
}
} else {
return JVMTI_ERROR_NOT_AVAILABLE;
}
}
}
return JVMTI_ERROR_NONE;
}
static int relinquishCapabilities(Pointer env, Pointer capabilitiesPtr) {
Pointer envCaps = CAPABILITIES.getPtr(env);
for (int i = 0; i < E.VALUES.length; i++) {
E cap = E.VALUES[i];
if (cap.get(capabilitiesPtr)) {
cap.set(envCaps, false);
}
}
return JVMTI_ERROR_NONE;
}
// JJVMTI variants
public static EnumSet<E> getPotentialCapabilities(JVMTI.JavaEnv env) throws JJVMTIException {
return E.allEnumSet;
}
public static void addCapabilities(JVMTI.JavaEnv env, EnumSet<E> caps) throws JJVMTIException {
for (E cap : caps) {
if (cap.can) {
env.capabilities.add(cap);
if (cap == E.CAN_MAINTAIN_ORIGINAL_METHOD_ORDER) {
ClassActor.preserveMethodActorOrder();
}
} else {
throw new JJVMTIException(JVMTI_ERROR_NOT_AVAILABLE);
}
}
}
public static void relinquishCapabilities(JVMTI.JavaEnv env, EnumSet<E> caps) throws JJVMTIException {
for (E cap : caps) {
env.capabilities.remove(cap);
}
}
}