alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (jvmtiEventController.cpp)

This example Java source code file (jvmtiEventController.cpp) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

ec_trace, javathread, jvmti, jvmti_trace, jvmtiframepop, jvmtithreadstate, jvmtithreadstate_lock\-, jvmtitrace\:\:safe_get_thread_name, mutexlocker, null, single_step_bit, thread_filtered_event_bits, threads\:\:number_of_threads, total_min_event_type_val

The jvmtiEventController.cpp Java example source code

/*
 * Copyright (c) 2003, 2013, 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.
 *
 */

#include "precompiled.hpp"
#include "interpreter/interpreter.hpp"
#include "jvmtifiles/jvmtiEnv.hpp"
#include "memory/resourceArea.hpp"
#include "prims/jvmtiEventController.hpp"
#include "prims/jvmtiEventController.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/jvmtiImpl.hpp"
#include "prims/jvmtiThreadState.inline.hpp"
#include "runtime/frame.hpp"
#include "runtime/thread.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vframe_hp.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"

#ifdef JVMTI_TRACE
#define EC_TRACE(out) do { \
  if (JvmtiTrace::trace_event_controller()) { \
    SafeResourceMark rm; \
    tty->print_cr out; \
  } \
} while (0)
#else
#define EC_TRACE(out)
#endif /*JVMTI_TRACE */

// bits for standard events

static const jlong  SINGLE_STEP_BIT = (((jlong)1) << (JVMTI_EVENT_SINGLE_STEP - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  FRAME_POP_BIT = (((jlong)1) << (JVMTI_EVENT_FRAME_POP - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  BREAKPOINT_BIT = (((jlong)1) << (JVMTI_EVENT_BREAKPOINT - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  FIELD_ACCESS_BIT = (((jlong)1) << (JVMTI_EVENT_FIELD_ACCESS - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  FIELD_MODIFICATION_BIT = (((jlong)1) << (JVMTI_EVENT_FIELD_MODIFICATION - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  METHOD_ENTRY_BIT = (((jlong)1) << (JVMTI_EVENT_METHOD_ENTRY - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  METHOD_EXIT_BIT = (((jlong)1) << (JVMTI_EVENT_METHOD_EXIT - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  CLASS_FILE_LOAD_HOOK_BIT = (((jlong)1) << (JVMTI_EVENT_CLASS_FILE_LOAD_HOOK - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  NATIVE_METHOD_BIND_BIT = (((jlong)1) << (JVMTI_EVENT_NATIVE_METHOD_BIND - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  VM_START_BIT = (((jlong)1) << (JVMTI_EVENT_VM_START - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  VM_INIT_BIT = (((jlong)1) << (JVMTI_EVENT_VM_INIT - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  VM_DEATH_BIT = (((jlong)1) << (JVMTI_EVENT_VM_DEATH - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  CLASS_LOAD_BIT = (((jlong)1) << (JVMTI_EVENT_CLASS_LOAD - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  CLASS_PREPARE_BIT = (((jlong)1) << (JVMTI_EVENT_CLASS_PREPARE - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  THREAD_START_BIT = (((jlong)1) << (JVMTI_EVENT_THREAD_START - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  THREAD_END_BIT = (((jlong)1) << (JVMTI_EVENT_THREAD_END - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  EXCEPTION_THROW_BIT = (((jlong)1) << (JVMTI_EVENT_EXCEPTION - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  EXCEPTION_CATCH_BIT = (((jlong)1) << (JVMTI_EVENT_EXCEPTION_CATCH - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  MONITOR_CONTENDED_ENTER_BIT = (((jlong)1) << (JVMTI_EVENT_MONITOR_CONTENDED_ENTER - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  MONITOR_CONTENDED_ENTERED_BIT = (((jlong)1) << (JVMTI_EVENT_MONITOR_CONTENDED_ENTERED - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  MONITOR_WAIT_BIT = (((jlong)1) << (JVMTI_EVENT_MONITOR_WAIT - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  MONITOR_WAITED_BIT = (((jlong)1) << (JVMTI_EVENT_MONITOR_WAITED - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  DYNAMIC_CODE_GENERATED_BIT = (((jlong)1) << (JVMTI_EVENT_DYNAMIC_CODE_GENERATED - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  DATA_DUMP_BIT = (((jlong)1) << (JVMTI_EVENT_DATA_DUMP_REQUEST - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  COMPILED_METHOD_LOAD_BIT = (((jlong)1) << (JVMTI_EVENT_COMPILED_METHOD_LOAD - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  COMPILED_METHOD_UNLOAD_BIT = (((jlong)1) << (JVMTI_EVENT_COMPILED_METHOD_UNLOAD - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  GARBAGE_COLLECTION_START_BIT = (((jlong)1) << (JVMTI_EVENT_GARBAGE_COLLECTION_START - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  GARBAGE_COLLECTION_FINISH_BIT = (((jlong)1) << (JVMTI_EVENT_GARBAGE_COLLECTION_FINISH - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  OBJECT_FREE_BIT = (((jlong)1) << (JVMTI_EVENT_OBJECT_FREE - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  RESOURCE_EXHAUSTED_BIT = (((jlong)1) << (JVMTI_EVENT_RESOURCE_EXHAUSTED - TOTAL_MIN_EVENT_TYPE_VAL));
static const jlong  VM_OBJECT_ALLOC_BIT = (((jlong)1) << (JVMTI_EVENT_VM_OBJECT_ALLOC - TOTAL_MIN_EVENT_TYPE_VAL));

// bits for extension events
static const jlong  CLASS_UNLOAD_BIT = (((jlong)1) << (EXT_EVENT_CLASS_UNLOAD - TOTAL_MIN_EVENT_TYPE_VAL));


static const jlong  MONITOR_BITS = MONITOR_CONTENDED_ENTER_BIT | MONITOR_CONTENDED_ENTERED_BIT |
                          MONITOR_WAIT_BIT | MONITOR_WAITED_BIT;
static const jlong  EXCEPTION_BITS = EXCEPTION_THROW_BIT | EXCEPTION_CATCH_BIT;
static const jlong  INTERP_EVENT_BITS =  SINGLE_STEP_BIT | METHOD_ENTRY_BIT | METHOD_EXIT_BIT |
                                FRAME_POP_BIT | FIELD_ACCESS_BIT | FIELD_MODIFICATION_BIT;
static const jlong  THREAD_FILTERED_EVENT_BITS = INTERP_EVENT_BITS | EXCEPTION_BITS | MONITOR_BITS |
                                        BREAKPOINT_BIT | CLASS_LOAD_BIT | CLASS_PREPARE_BIT | THREAD_END_BIT;
static const jlong  NEED_THREAD_LIFE_EVENTS = THREAD_FILTERED_EVENT_BITS | THREAD_START_BIT;
static const jlong  EARLY_EVENT_BITS = CLASS_FILE_LOAD_HOOK_BIT |
                               VM_START_BIT | VM_INIT_BIT | VM_DEATH_BIT | NATIVE_METHOD_BIND_BIT |
                               THREAD_START_BIT | THREAD_END_BIT |
                               DYNAMIC_CODE_GENERATED_BIT;
static const jlong  GLOBAL_EVENT_BITS = ~THREAD_FILTERED_EVENT_BITS;
static const jlong  SHOULD_POST_ON_EXCEPTIONS_BITS = EXCEPTION_BITS | METHOD_EXIT_BIT | FRAME_POP_BIT;

///////////////////////////////////////////////////////////////
//
// JvmtiEventEnabled
//

JvmtiEventEnabled::JvmtiEventEnabled() {
  clear();
}


void JvmtiEventEnabled::clear() {
  _enabled_bits = 0;
#ifndef PRODUCT
  _init_guard = JEE_INIT_GUARD;
#endif
}

void JvmtiEventEnabled::set_enabled(jvmtiEvent event_type, bool enabled) {
  jlong bits = get_bits();
  jlong mask = bit_for(event_type);
  if (enabled) {
    bits |= mask;
  } else {
    bits &= ~mask;
  }
  set_bits(bits);
}


///////////////////////////////////////////////////////////////
//
// JvmtiEnvThreadEventEnable
//

JvmtiEnvThreadEventEnable::JvmtiEnvThreadEventEnable() {
  _event_user_enabled.clear();
  _event_enabled.clear();
}


JvmtiEnvThreadEventEnable::~JvmtiEnvThreadEventEnable() {
  _event_user_enabled.clear();
  _event_enabled.clear();
}


///////////////////////////////////////////////////////////////
//
// JvmtiThreadEventEnable
//

JvmtiThreadEventEnable::JvmtiThreadEventEnable() {
  _event_enabled.clear();
}


JvmtiThreadEventEnable::~JvmtiThreadEventEnable() {
  _event_enabled.clear();
}


///////////////////////////////////////////////////////////////
//
// JvmtiEnvEventEnable
//

JvmtiEnvEventEnable::JvmtiEnvEventEnable() {
  _event_user_enabled.clear();
  _event_callback_enabled.clear();
  _event_enabled.clear();
}


JvmtiEnvEventEnable::~JvmtiEnvEventEnable() {
  _event_user_enabled.clear();
  _event_callback_enabled.clear();
  _event_enabled.clear();
}


///////////////////////////////////////////////////////////////
//
// VM_EnterInterpOnlyMode
//

class VM_EnterInterpOnlyMode : public VM_Operation {
private:
  JvmtiThreadState *_state;

public:
  VM_EnterInterpOnlyMode(JvmtiThreadState *state);

  bool allow_nested_vm_operations() const        { return true; }
  VMOp_Type type() const { return VMOp_EnterInterpOnlyMode; }
  void doit();

  // to do: this same function is in jvmtiImpl - should be in one place
  bool can_be_deoptimized(vframe* vf) {
    return (vf->is_compiled_frame() && vf->fr().can_be_deoptimized());
  }
};

VM_EnterInterpOnlyMode::VM_EnterInterpOnlyMode(JvmtiThreadState *state)
  : _state(state)
{
}


void VM_EnterInterpOnlyMode::doit() {
  // Set up the current stack depth for later tracking
  _state->invalidate_cur_stack_depth();

  _state->enter_interp_only_mode();

  JavaThread *thread = _state->get_thread();
  if (thread->has_last_Java_frame()) {
    // If running in fullspeed mode, single stepping is implemented
    // as follows: first, the interpreter does not dispatch to
    // compiled code for threads that have single stepping enabled;
    // second, we deoptimize all methods on the thread's stack when
    // interpreted-only mode is enabled the first time for a given
    // thread (nothing to do if no Java frames yet).
    int num_marked = 0;
    ResourceMark resMark;
    RegisterMap rm(thread, false);
    for (vframe* vf = thread->last_java_vframe(&rm); vf; vf = vf->sender()) {
      if (can_be_deoptimized(vf)) {
        ((compiledVFrame*) vf)->code()->mark_for_deoptimization();
        ++num_marked;
      }
    }
    if (num_marked > 0) {
      VM_Deoptimize op;
      VMThread::execute(&op);
    }
  }
}


///////////////////////////////////////////////////////////////
//
// VM_ChangeSingleStep
//

class VM_ChangeSingleStep : public VM_Operation {
private:
  bool _on;

public:
  VM_ChangeSingleStep(bool on);
  VMOp_Type type() const                         { return VMOp_ChangeSingleStep; }
  bool allow_nested_vm_operations() const        { return true; }
  void doit();   // method definition is after definition of JvmtiEventControllerPrivate because of scoping
};


VM_ChangeSingleStep::VM_ChangeSingleStep(bool on)
  : _on(on != 0)
{
}




///////////////////////////////////////////////////////////////
//
// JvmtiEventControllerPrivate
//
// Private internal implementation methods for JvmtiEventController.
//
// These methods are thread safe either because they are called
// in early VM initialization which is single threaded, or they
// hold the JvmtiThreadState_lock.
//

class JvmtiEventControllerPrivate : public AllStatic {
  static bool _initialized;
public:
  static void set_should_post_single_step(bool on);
  static void enter_interp_only_mode(JvmtiThreadState *state);
  static void leave_interp_only_mode(JvmtiThreadState *state);
  static void recompute_enabled();
  static jlong recompute_env_enabled(JvmtiEnvBase* env);
  static jlong recompute_env_thread_enabled(JvmtiEnvThreadState* ets, JvmtiThreadState* state);
  static jlong recompute_thread_enabled(JvmtiThreadState *state);
  static void event_init();

  static void set_user_enabled(JvmtiEnvBase *env, JavaThread *thread,
                        jvmtiEvent event_type, bool enabled);
  static void set_event_callbacks(JvmtiEnvBase *env,
                                  const jvmtiEventCallbacks* callbacks,
                                  jint size_of_callbacks);

  static void set_extension_event_callback(JvmtiEnvBase *env,
                                           jint extension_event_index,
                                           jvmtiExtensionEvent callback);

  static void set_frame_pop(JvmtiEnvThreadState *env_thread, JvmtiFramePop fpop);
  static void clear_frame_pop(JvmtiEnvThreadState *env_thread, JvmtiFramePop fpop);
  static void clear_to_frame_pop(JvmtiEnvThreadState *env_thread, JvmtiFramePop fpop);
  static void change_field_watch(jvmtiEvent event_type, bool added);

  static void thread_started(JavaThread *thread);
  static void thread_ended(JavaThread *thread);

  static void env_initialize(JvmtiEnvBase *env);
  static void env_dispose(JvmtiEnvBase *env);

  static void vm_start();
  static void vm_init();
  static void vm_death();

  static void trace_changed(JvmtiThreadState *state, jlong now_enabled, jlong changed);
  static void trace_changed(jlong now_enabled, jlong changed);
};

bool JvmtiEventControllerPrivate::_initialized = false;

void JvmtiEventControllerPrivate::set_should_post_single_step(bool on) {
  // we have permission to do this, VM op doesn't
  JvmtiExport::set_should_post_single_step(on);
}


// This change must always be occur when at a safepoint.
// Being at a safepoint causes the interpreter to use the
// safepoint dispatch table which we overload to find single
// step points.  Just to be sure that it has been set, we
// call notice_safepoints when turning on single stepping.
// When we leave our current safepoint, should_post_single_step
// will be checked by the interpreter, and the table kept
// or changed accordingly.
void VM_ChangeSingleStep::doit() {
  JvmtiEventControllerPrivate::set_should_post_single_step(_on);
  if (_on) {
    Interpreter::notice_safepoints();
  }
}


void JvmtiEventControllerPrivate::enter_interp_only_mode(JvmtiThreadState *state) {
  EC_TRACE(("JVMTI [%s] # Entering interpreter only mode",
            JvmtiTrace::safe_get_thread_name(state->get_thread())));

  VM_EnterInterpOnlyMode op(state);
  VMThread::execute(&op);
}


void
JvmtiEventControllerPrivate::leave_interp_only_mode(JvmtiThreadState *state) {
  EC_TRACE(("JVMTI [%s] # Leaving interpreter only mode",
            JvmtiTrace::safe_get_thread_name(state->get_thread())));
  state->leave_interp_only_mode();
}


void
JvmtiEventControllerPrivate::trace_changed(JvmtiThreadState *state, jlong now_enabled, jlong changed) {
#ifdef JVMTI_TRACE
  if (JvmtiTrace::trace_event_controller()) {
    SafeResourceMark rm;
    // traces standard events only
    for (int ei = JVMTI_MIN_EVENT_TYPE_VAL; ei <= JVMTI_MAX_EVENT_TYPE_VAL; ++ei) {
      jlong bit = JvmtiEventEnabled::bit_for((jvmtiEvent)ei);
      if (changed & bit) {
        // it changed, print it
        tty->print_cr("JVMTI [%s] # %s event %s",
                      JvmtiTrace::safe_get_thread_name(state->get_thread()),
                      (now_enabled & bit)? "Enabling" : "Disabling", JvmtiTrace::event_name((jvmtiEvent)ei));
      }
    }
  }
#endif /*JVMTI_TRACE */
}


void
JvmtiEventControllerPrivate::trace_changed(jlong now_enabled, jlong changed) {
#ifdef JVMTI_TRACE
  if (JvmtiTrace::trace_event_controller()) {
    SafeResourceMark rm;
    // traces standard events only
    for (int ei = JVMTI_MIN_EVENT_TYPE_VAL; ei <= JVMTI_MAX_EVENT_TYPE_VAL; ++ei) {
      jlong bit = JvmtiEventEnabled::bit_for((jvmtiEvent)ei);
      if (changed & bit) {
        // it changed, print it
        tty->print_cr("JVMTI [-] # %s event %s",
                      (now_enabled & bit)? "Enabling" : "Disabling", JvmtiTrace::event_name((jvmtiEvent)ei));
      }
    }
  }
#endif /*JVMTI_TRACE */
}


// For the specified env: compute the currently truly enabled events
// set external state accordingly.
// Return value and set value must include all events.
// But outside this class, only non-thread-filtered events can be queried..
jlong
JvmtiEventControllerPrivate::recompute_env_enabled(JvmtiEnvBase* env) {
  jlong was_enabled = env->env_event_enable()->_event_enabled.get_bits();
  jlong now_enabled =
    env->env_event_enable()->_event_callback_enabled.get_bits() &
    env->env_event_enable()->_event_user_enabled.get_bits();

  switch (JvmtiEnv::get_phase()) {
  case JVMTI_PHASE_PRIMORDIAL:
  case JVMTI_PHASE_ONLOAD:
    // only these events allowed in primordial or onload phase
    now_enabled &= (EARLY_EVENT_BITS & ~THREAD_FILTERED_EVENT_BITS);
    break;
  case JVMTI_PHASE_START:
    // only these events allowed in start phase
    now_enabled &= EARLY_EVENT_BITS;
    break;
  case JVMTI_PHASE_LIVE:
    // all events allowed during live phase
    break;
  case JVMTI_PHASE_DEAD:
    // no events allowed when dead
    now_enabled = 0;
    break;
  default:
    assert(false, "no other phases - sanity check");
    break;
  }

  // will we really send these events to this env
  env->env_event_enable()->_event_enabled.set_bits(now_enabled);

  trace_changed(now_enabled, (now_enabled ^ was_enabled)  & ~THREAD_FILTERED_EVENT_BITS);

  return now_enabled;
}


// For the specified env and thread: compute the currently truly enabled events
// set external state accordingly.  Only thread-filtered events are included.
jlong
JvmtiEventControllerPrivate::recompute_env_thread_enabled(JvmtiEnvThreadState* ets, JvmtiThreadState* state) {
  JvmtiEnv *env = ets->get_env();

  jlong was_enabled = ets->event_enable()->_event_enabled.get_bits();
  jlong now_enabled =  THREAD_FILTERED_EVENT_BITS &
    env->env_event_enable()->_event_callback_enabled.get_bits() &
    (env->env_event_enable()->_event_user_enabled.get_bits() |
     ets->event_enable()->_event_user_enabled.get_bits());

  // for frame pops and field watchs, computed enabled state
  // is only true if an event has been requested
  if (!ets->has_frame_pops()) {
    now_enabled &= ~FRAME_POP_BIT;
  }
  if (*((int *)JvmtiExport::get_field_access_count_addr()) == 0) {
    now_enabled &= ~FIELD_ACCESS_BIT;
  }
  if (*((int *)JvmtiExport::get_field_modification_count_addr()) == 0) {
    now_enabled &= ~FIELD_MODIFICATION_BIT;
  }

  switch (JvmtiEnv::get_phase()) {
  case JVMTI_PHASE_DEAD:
    // no events allowed when dead
    now_enabled = 0;
    break;
  }

  // if anything changed do update
  if (now_enabled != was_enabled) {

    // will we really send these events to this thread x env
    ets->event_enable()->_event_enabled.set_bits(now_enabled);

    // If the enabled status of the single step or breakpoint events changed,
    // the location status may need to change as well.
    jlong changed = now_enabled ^ was_enabled;
    if (changed & SINGLE_STEP_BIT) {
      ets->reset_current_location(JVMTI_EVENT_SINGLE_STEP, (now_enabled & SINGLE_STEP_BIT) != 0);
    }
    if (changed & BREAKPOINT_BIT) {
      ets->reset_current_location(JVMTI_EVENT_BREAKPOINT,  (now_enabled & BREAKPOINT_BIT) != 0);
    }
    trace_changed(state, now_enabled, changed);
  }
  return now_enabled;
}


// For the specified thread: compute the currently truly enabled events
// set external state accordingly.  Only thread-filtered events are included.
jlong
JvmtiEventControllerPrivate::recompute_thread_enabled(JvmtiThreadState *state) {
  if (state == NULL) {
    // associated JavaThread is exiting
    return (jlong)0;
  }

  jlong was_any_env_enabled = state->thread_event_enable()->_event_enabled.get_bits();
  jlong any_env_enabled = 0;

  {
    // This iteration will include JvmtiEnvThreadStates whoses environments
    // have been disposed.  These JvmtiEnvThreadStates must not be filtered
    // as recompute must be called on them to disable their events,
    JvmtiEnvThreadStateIterator it(state);
    for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) {
      any_env_enabled |= recompute_env_thread_enabled(ets, state);
    }
  }

  if (any_env_enabled != was_any_env_enabled) {
    // mark if event is truly enabled on this thread in any environment
    state->thread_event_enable()->_event_enabled.set_bits(any_env_enabled);

    // compute interp_only mode
    bool should_be_interp = (any_env_enabled & INTERP_EVENT_BITS) != 0;
    bool is_now_interp = state->is_interp_only_mode();

    if (should_be_interp != is_now_interp) {
      if (should_be_interp) {
        enter_interp_only_mode(state);
      } else {
        leave_interp_only_mode(state);
      }
    }

    // update the JavaThread cached value for thread-specific should_post_on_exceptions value
    bool should_post_on_exceptions = (any_env_enabled & SHOULD_POST_ON_EXCEPTIONS_BITS) != 0;
    state->set_should_post_on_exceptions(should_post_on_exceptions);
  }

  return any_env_enabled;
}


// Compute truly enabled events - meaning if the event can and could be
// sent.  An event is truly enabled if it is user enabled on the thread
// or globally user enabled, but only if there is a callback or event hook
// for it and, for field watch and frame pop, one has been set.
// Compute if truly enabled, per thread, per environment, per combination
// (thread x environment), and overall.  These merges are true if any is true.
// True per thread if some environment has callback set and the event is globally
// enabled or enabled for this thread.
// True per environment if the callback is set and the event is globally
// enabled in this environment or enabled for any thread in this environment.
// True per combination if the environment has the callback set and the
// event is globally enabled in this environment or the event is enabled
// for this thread and environment.
//
// All states transitions dependent on these transitions are also handled here.
void
JvmtiEventControllerPrivate::recompute_enabled() {
  assert(Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked(), "sanity check");

  // event enabled for any thread in any environment
  jlong was_any_env_thread_enabled = JvmtiEventController::_universal_global_event_enabled.get_bits();
  jlong any_env_thread_enabled = 0;

  EC_TRACE(("JVMTI [-] # recompute enabled - before %llx", was_any_env_thread_enabled));

  // compute non-thread-filters events.
  // This must be done separately from thread-filtered events, since some
  // events can occur before any threads exist.
  JvmtiEnvIterator it;
  for (JvmtiEnvBase* env = it.first(); env != NULL; env = it.next(env)) {
    any_env_thread_enabled |= recompute_env_enabled(env);
  }

  // We need to create any missing jvmti_thread_state if there are globally set thread
  // filtered events and there weren't last time
  if (    (any_env_thread_enabled & THREAD_FILTERED_EVENT_BITS) != 0 &&
      (was_any_env_thread_enabled & THREAD_FILTERED_EVENT_BITS) == 0) {
    assert(JvmtiEnv::is_vm_live() || (JvmtiEnv::get_phase()==JVMTI_PHASE_START),
      "thread filtered events should not be enabled when VM not in start or live phase");
    {
      MutexLocker mu(Threads_lock);   //hold the Threads_lock for the iteration
      for (JavaThread *tp = Threads::first(); tp != NULL; tp = tp->next()) {
        // state_for_while_locked() makes tp->is_exiting() check
        JvmtiThreadState::state_for_while_locked(tp);  // create the thread state if missing
      }
    }// release Threads_lock
  }

  // compute and set thread-filtered events
  for (JvmtiThreadState *state = JvmtiThreadState::first(); state != NULL; state = state->next()) {
    any_env_thread_enabled |= recompute_thread_enabled(state);
  }

  // set universal state (across all envs and threads)
  jlong delta = any_env_thread_enabled ^ was_any_env_thread_enabled;
  if (delta != 0) {
    JvmtiExport::set_should_post_field_access((any_env_thread_enabled & FIELD_ACCESS_BIT) != 0);
    JvmtiExport::set_should_post_field_modification((any_env_thread_enabled & FIELD_MODIFICATION_BIT) != 0);
    JvmtiExport::set_should_post_class_load((any_env_thread_enabled & CLASS_LOAD_BIT) != 0);
    JvmtiExport::set_should_post_class_file_load_hook((any_env_thread_enabled & CLASS_FILE_LOAD_HOOK_BIT) != 0);
    JvmtiExport::set_should_post_native_method_bind((any_env_thread_enabled & NATIVE_METHOD_BIND_BIT) != 0);
    JvmtiExport::set_should_post_dynamic_code_generated((any_env_thread_enabled & DYNAMIC_CODE_GENERATED_BIT) != 0);
    JvmtiExport::set_should_post_data_dump((any_env_thread_enabled & DATA_DUMP_BIT) != 0);
    JvmtiExport::set_should_post_class_prepare((any_env_thread_enabled & CLASS_PREPARE_BIT) != 0);
    JvmtiExport::set_should_post_class_unload((any_env_thread_enabled & CLASS_UNLOAD_BIT) != 0);
    JvmtiExport::set_should_post_monitor_contended_enter((any_env_thread_enabled & MONITOR_CONTENDED_ENTER_BIT) != 0);
    JvmtiExport::set_should_post_monitor_contended_entered((any_env_thread_enabled & MONITOR_CONTENDED_ENTERED_BIT) != 0);
    JvmtiExport::set_should_post_monitor_wait((any_env_thread_enabled & MONITOR_WAIT_BIT) != 0);
    JvmtiExport::set_should_post_monitor_waited((any_env_thread_enabled & MONITOR_WAITED_BIT) != 0);
    JvmtiExport::set_should_post_garbage_collection_start((any_env_thread_enabled & GARBAGE_COLLECTION_START_BIT) != 0);
    JvmtiExport::set_should_post_garbage_collection_finish((any_env_thread_enabled & GARBAGE_COLLECTION_FINISH_BIT) != 0);
    JvmtiExport::set_should_post_object_free((any_env_thread_enabled & OBJECT_FREE_BIT) != 0);
    JvmtiExport::set_should_post_resource_exhausted((any_env_thread_enabled & RESOURCE_EXHAUSTED_BIT) != 0);
    JvmtiExport::set_should_post_compiled_method_load((any_env_thread_enabled & COMPILED_METHOD_LOAD_BIT) != 0);
    JvmtiExport::set_should_post_compiled_method_unload((any_env_thread_enabled & COMPILED_METHOD_UNLOAD_BIT) != 0);
    JvmtiExport::set_should_post_vm_object_alloc((any_env_thread_enabled & VM_OBJECT_ALLOC_BIT) != 0);

    // need this if we want thread events or we need them to init data
    JvmtiExport::set_should_post_thread_life((any_env_thread_enabled & NEED_THREAD_LIFE_EVENTS) != 0);

    // If single stepping is turned on or off, execute the VM op to change it.
    if (delta & SINGLE_STEP_BIT) {
      switch (JvmtiEnv::get_phase()) {
      case JVMTI_PHASE_DEAD:
        // If the VM is dying we can't execute VM ops
        break;
      case JVMTI_PHASE_LIVE: {
        VM_ChangeSingleStep op((any_env_thread_enabled & SINGLE_STEP_BIT) != 0);
        VMThread::execute(&op);
        break;
      }
      default:
        assert(false, "should never come here before live phase");
        break;
      }
    }

    // set global truly enabled, that is, any thread in any environment
    JvmtiEventController::_universal_global_event_enabled.set_bits(any_env_thread_enabled);

    // set global should_post_on_exceptions
    JvmtiExport::set_should_post_on_exceptions((any_env_thread_enabled & SHOULD_POST_ON_EXCEPTIONS_BITS) != 0);

  }

  EC_TRACE(("JVMTI [-] # recompute enabled - after %llx", any_env_thread_enabled));
}


void
JvmtiEventControllerPrivate::thread_started(JavaThread *thread) {
  assert(thread->is_Java_thread(), "Must be JavaThread");
  assert(thread == Thread::current(), "must be current thread");
  assert(JvmtiEnvBase::environments_might_exist(), "to enter event controller, JVM TI environments must exist");

  EC_TRACE(("JVMTI [%s] # thread started", JvmtiTrace::safe_get_thread_name(thread)));

  // if we have any thread filtered events globally enabled, create/update the thread state
  if ((JvmtiEventController::_universal_global_event_enabled.get_bits() & THREAD_FILTERED_EVENT_BITS) != 0) {
    MutexLocker mu(JvmtiThreadState_lock);
    // create the thread state if missing
    JvmtiThreadState *state = JvmtiThreadState::state_for_while_locked(thread);
    if (state != NULL) {    // skip threads with no JVMTI thread state
      recompute_thread_enabled(state);
    }
  }
}


void
JvmtiEventControllerPrivate::thread_ended(JavaThread *thread) {
  // Removes the JvmtiThreadState associated with the specified thread.
  // May be called after all environments have been disposed.
  assert(JvmtiThreadState_lock->is_locked(), "sanity check");

  EC_TRACE(("JVMTI [%s] # thread ended", JvmtiTrace::safe_get_thread_name(thread)));

  JvmtiThreadState *state = thread->jvmti_thread_state();
  assert(state != NULL, "else why are we here?");
  delete state;
}

void JvmtiEventControllerPrivate::set_event_callbacks(JvmtiEnvBase *env,
                                                      const jvmtiEventCallbacks* callbacks,
                                                      jint size_of_callbacks) {
  assert(Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked(), "sanity check");
  EC_TRACE(("JVMTI [*] # set event callbacks"));

  env->set_event_callbacks(callbacks, size_of_callbacks);
  jlong enabled_bits = 0;
  for (int ei = JVMTI_MIN_EVENT_TYPE_VAL; ei <= JVMTI_MAX_EVENT_TYPE_VAL; ++ei) {
    jvmtiEvent evt_t = (jvmtiEvent)ei;
    if (env->has_callback(evt_t)) {
      enabled_bits |= JvmtiEventEnabled::bit_for(evt_t);
    }
  }
  env->env_event_enable()->_event_callback_enabled.set_bits(enabled_bits);
  recompute_enabled();
}

void
JvmtiEventControllerPrivate::set_extension_event_callback(JvmtiEnvBase *env,
                                                          jint extension_event_index,
                                                          jvmtiExtensionEvent callback)
{
  assert(Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked(), "sanity check");
  EC_TRACE(("JVMTI [*] # set extension event callback"));

  // extension events are allocated below JVMTI_MIN_EVENT_TYPE_VAL
  assert(extension_event_index >= (jint)EXT_MIN_EVENT_TYPE_VAL &&
         extension_event_index <= (jint)EXT_MAX_EVENT_TYPE_VAL, "sanity check");


  // As the bits for both standard (jvmtiEvent) and extension
  // (jvmtiExtEvents) are stored in the same word we cast here to
  // jvmtiEvent to set/clear the bit for this extension event.
  jvmtiEvent event_type = (jvmtiEvent)extension_event_index;

  // Prevent a possible race condition where events are re-enabled by a call to
  // set event callbacks, where the DisposeEnvironment occurs after the boiler-plate
  // environment check and before the lock is acquired.
  // We can safely do the is_valid check now, as JvmtiThreadState_lock is held.
  bool enabling = (callback != NULL) && (env->is_valid());
  env->env_event_enable()->set_user_enabled(event_type, enabling);

  // update the callback
  jvmtiExtEventCallbacks* ext_callbacks = env->ext_callbacks();
  switch (extension_event_index) {
    case EXT_EVENT_CLASS_UNLOAD :
      ext_callbacks->ClassUnload = callback;
      break;
    default:
      ShouldNotReachHere();
  }

  // update the callback enable/disable bit
  jlong enabled_bits = env->env_event_enable()->_event_callback_enabled.get_bits();
  jlong bit_for = JvmtiEventEnabled::bit_for(event_type);
  if (enabling) {
    enabled_bits |= bit_for;
  } else {
    enabled_bits &= ~bit_for;
  }
  env->env_event_enable()->_event_callback_enabled.set_bits(enabled_bits);

  recompute_enabled();
}


void
JvmtiEventControllerPrivate::env_initialize(JvmtiEnvBase *env) {
  assert(Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked(), "sanity check");
  EC_TRACE(("JVMTI [*] # env initialize"));

  if (JvmtiEnvBase::is_vm_live()) {
    // if we didn't initialize event info already (this is a late
    // launched environment), do it now.
    event_init();
  }

  env->initialize();

  // add the JvmtiEnvThreadState to each JvmtiThreadState
  for (JvmtiThreadState *state = JvmtiThreadState::first(); state != NULL; state = state->next()) {
    state->add_env(env);
    assert((JvmtiEnv*)(state->env_thread_state(env)->get_env()) == env, "sanity check");
  }
  JvmtiEventControllerPrivate::recompute_enabled();
}


void
JvmtiEventControllerPrivate::env_dispose(JvmtiEnvBase *env) {
  assert(Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked(), "sanity check");
  EC_TRACE(("JVMTI [*] # env dispose"));

  // Before the environment is marked disposed, disable all events on this
  // environment (by zapping the callbacks).  As a result, the disposed
  // environment will not call event handlers.
  set_event_callbacks(env, NULL, 0);
  for (jint extension_event_index = EXT_MIN_EVENT_TYPE_VAL;
       extension_event_index <= EXT_MAX_EVENT_TYPE_VAL;
       ++extension_event_index) {
    set_extension_event_callback(env, extension_event_index, NULL);
  }

  // Let the environment finish disposing itself.
  env->env_dispose();
}


void
JvmtiEventControllerPrivate::set_user_enabled(JvmtiEnvBase *env, JavaThread *thread,
                                          jvmtiEvent event_type, bool enabled) {
  assert(Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked(), "sanity check");

  EC_TRACE(("JVMTI [%s] # user %s event %s",
            thread==NULL? "ALL": JvmtiTrace::safe_get_thread_name(thread),
            enabled? "enabled" : "disabled", JvmtiTrace::event_name(event_type)));

  if (thread == NULL) {
    env->env_event_enable()->set_user_enabled(event_type, enabled);
  } else {
    // create the thread state (if it didn't exist before)
    JvmtiThreadState *state = JvmtiThreadState::state_for_while_locked(thread);
    if (state != NULL) {
      state->env_thread_state(env)->event_enable()->set_user_enabled(event_type, enabled);
    }
  }
  recompute_enabled();
}


void
JvmtiEventControllerPrivate::set_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
  EC_TRACE(("JVMTI [%s] # set frame pop - frame=%d",
            JvmtiTrace::safe_get_thread_name(ets->get_thread()),
            fpop.frame_number() ));

  ets->get_frame_pops()->set(fpop);
  recompute_thread_enabled(ets->get_thread()->jvmti_thread_state());
}


void
JvmtiEventControllerPrivate::clear_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
  EC_TRACE(("JVMTI [%s] # clear frame pop - frame=%d",
            JvmtiTrace::safe_get_thread_name(ets->get_thread()),
            fpop.frame_number() ));

  ets->get_frame_pops()->clear(fpop);
  recompute_thread_enabled(ets->get_thread()->jvmti_thread_state());
}


void
JvmtiEventControllerPrivate::clear_to_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
  int cleared_cnt = ets->get_frame_pops()->clear_to(fpop);

  EC_TRACE(("JVMTI [%s] # clear to frame pop - frame=%d, count=%d",
            JvmtiTrace::safe_get_thread_name(ets->get_thread()),
            fpop.frame_number(),
            cleared_cnt ));

  if (cleared_cnt > 0) {
    recompute_thread_enabled(ets->get_thread()->jvmti_thread_state());
  }
}

void
JvmtiEventControllerPrivate::change_field_watch(jvmtiEvent event_type, bool added) {
  int *count_addr;

  switch (event_type) {
  case JVMTI_EVENT_FIELD_MODIFICATION:
    count_addr = (int *)JvmtiExport::get_field_modification_count_addr();
    break;
  case JVMTI_EVENT_FIELD_ACCESS:
    count_addr = (int *)JvmtiExport::get_field_access_count_addr();
    break;
  default:
    assert(false, "incorrect event");
    return;
  }

  EC_TRACE(("JVMTI [-] # change field watch - %s %s count=%d",
            event_type==JVMTI_EVENT_FIELD_MODIFICATION? "modification" : "access",
            added? "add" : "remove",
            *count_addr));

  if (added) {
    (*count_addr)++;
    if (*count_addr == 1) {
      recompute_enabled();
    }
  } else {
    if (*count_addr > 0) {
      (*count_addr)--;
      if (*count_addr == 0) {
        recompute_enabled();
      }
    } else {
      assert(false, "field watch out of phase");
    }
  }
}

void
JvmtiEventControllerPrivate::event_init() {
  assert(JvmtiThreadState_lock->is_locked(), "sanity check");

  if (_initialized) {
    return;
  }

  EC_TRACE(("JVMTI [-] # VM live"));

#ifdef ASSERT
  // check that our idea and the spec's idea of threaded events match
  for (int ei = JVMTI_MIN_EVENT_TYPE_VAL; ei <= JVMTI_MAX_EVENT_TYPE_VAL; ++ei) {
    jlong bit = JvmtiEventEnabled::bit_for((jvmtiEvent)ei);
    assert(((THREAD_FILTERED_EVENT_BITS & bit) != 0) == JvmtiUtil::event_threaded(ei),
           "thread filtered event list does not match");
  }
#endif

  _initialized = true;
}

void
JvmtiEventControllerPrivate::vm_start() {
  // some events are now able to be enabled (phase has changed)
  JvmtiEventControllerPrivate::recompute_enabled();
}


void
JvmtiEventControllerPrivate::vm_init() {
  event_init();

  // all the events are now able to be enabled (phase has changed)
  JvmtiEventControllerPrivate::recompute_enabled();
}


void
JvmtiEventControllerPrivate::vm_death() {
  // events are disabled (phase has changed)
  JvmtiEventControllerPrivate::recompute_enabled();
}


///////////////////////////////////////////////////////////////
//
// JvmtiEventController
//

JvmtiEventEnabled JvmtiEventController::_universal_global_event_enabled;

bool
JvmtiEventController::is_global_event(jvmtiEvent event_type) {
  assert(is_valid_event_type(event_type), "invalid event type");
  jlong bit_for = ((jlong)1) << (event_type - TOTAL_MIN_EVENT_TYPE_VAL);
  return((bit_for & GLOBAL_EVENT_BITS)!=0);
}

void
JvmtiEventController::set_user_enabled(JvmtiEnvBase *env, JavaThread *thread, jvmtiEvent event_type, bool enabled) {
  if (Threads::number_of_threads() == 0) {
    // during early VM start-up locks don't exist, but we are safely single threaded,
    // call the functionality without holding the JvmtiThreadState_lock.
    JvmtiEventControllerPrivate::set_user_enabled(env, thread, event_type, enabled);
  } else {
    MutexLocker mu(JvmtiThreadState_lock);
    JvmtiEventControllerPrivate::set_user_enabled(env, thread, event_type, enabled);
  }
}


void
JvmtiEventController::set_event_callbacks(JvmtiEnvBase *env,
                                          const jvmtiEventCallbacks* callbacks,
                                          jint size_of_callbacks) {
  if (Threads::number_of_threads() == 0) {
    // during early VM start-up locks don't exist, but we are safely single threaded,
    // call the functionality without holding the JvmtiThreadState_lock.
    JvmtiEventControllerPrivate::set_event_callbacks(env, callbacks, size_of_callbacks);
  } else {
    MutexLocker mu(JvmtiThreadState_lock);
    JvmtiEventControllerPrivate::set_event_callbacks(env, callbacks, size_of_callbacks);
  }
}

void
JvmtiEventController::set_extension_event_callback(JvmtiEnvBase *env,
                                                   jint extension_event_index,
                                                   jvmtiExtensionEvent callback) {
  if (Threads::number_of_threads() == 0) {
    JvmtiEventControllerPrivate::set_extension_event_callback(env, extension_event_index, callback);
  } else {
    MutexLocker mu(JvmtiThreadState_lock);
    JvmtiEventControllerPrivate::set_extension_event_callback(env, extension_event_index, callback);
  }
}




void
JvmtiEventController::set_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
  MutexLocker mu(JvmtiThreadState_lock);
  JvmtiEventControllerPrivate::set_frame_pop(ets, fpop);
}


void
JvmtiEventController::clear_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
  MutexLocker mu(JvmtiThreadState_lock);
  JvmtiEventControllerPrivate::clear_frame_pop(ets, fpop);
}


void
JvmtiEventController::clear_to_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
  MutexLocker mu(JvmtiThreadState_lock);
  JvmtiEventControllerPrivate::clear_to_frame_pop(ets, fpop);
}

void
JvmtiEventController::change_field_watch(jvmtiEvent event_type, bool added) {
  MutexLocker mu(JvmtiThreadState_lock);
  JvmtiEventControllerPrivate::change_field_watch(event_type, added);
}

void
JvmtiEventController::thread_started(JavaThread *thread) {
  // operates only on the current thread
  // JvmtiThreadState_lock grabbed only if needed.
  JvmtiEventControllerPrivate::thread_started(thread);
}

void
JvmtiEventController::thread_ended(JavaThread *thread) {
  // operates only on the current thread
  // JvmtiThreadState_lock grabbed only if needed.
  JvmtiEventControllerPrivate::thread_ended(thread);
}

void
JvmtiEventController::env_initialize(JvmtiEnvBase *env) {
  if (Threads::number_of_threads() == 0) {
    // during early VM start-up locks don't exist, but we are safely single threaded,
    // call the functionality without holding the JvmtiThreadState_lock.
    JvmtiEventControllerPrivate::env_initialize(env);
  } else {
    MutexLocker mu(JvmtiThreadState_lock);
    JvmtiEventControllerPrivate::env_initialize(env);
  }
}

void
JvmtiEventController::env_dispose(JvmtiEnvBase *env) {
  if (Threads::number_of_threads() == 0) {
    // during early VM start-up locks don't exist, but we are safely single threaded,
    // call the functionality without holding the JvmtiThreadState_lock.
    JvmtiEventControllerPrivate::env_dispose(env);
  } else {
    MutexLocker mu(JvmtiThreadState_lock);
    JvmtiEventControllerPrivate::env_dispose(env);
  }
}


void
JvmtiEventController::vm_start() {
  if (JvmtiEnvBase::environments_might_exist()) {
    MutexLocker mu(JvmtiThreadState_lock);
    JvmtiEventControllerPrivate::vm_start();
  }
}

void
JvmtiEventController::vm_init() {
  if (JvmtiEnvBase::environments_might_exist()) {
    MutexLocker mu(JvmtiThreadState_lock);
    JvmtiEventControllerPrivate::vm_init();
  }
}

void
JvmtiEventController::vm_death() {
  if (JvmtiEnvBase::environments_might_exist()) {
    MutexLocker mu(JvmtiThreadState_lock);
    JvmtiEventControllerPrivate::vm_death();
  }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java jvmtiEventController.cpp source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.