/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_
#define ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_

#include <array>

#include "events.h"

#include "art_jvmti.h"

namespace openjdkjvmti {

static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, jvmtiEvent e) {
  if (UNLIKELY(e == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK)) {
    if (env->capabilities.can_retransform_classes) {
      return ArtJvmtiEvent::kClassFileLoadHookRetransformable;
    } else {
      return ArtJvmtiEvent::kClassFileLoadHookNonRetransformable;
    }
  } else {
    return static_cast<ArtJvmtiEvent>(e);
  }
}

namespace impl {

// Infrastructure to achieve type safety for event dispatch.

#define FORALL_EVENT_TYPES(fn)                                                       \
  fn(VMInit,                  ArtJvmtiEvent::kVmInit)                                \
  fn(VMDeath,                 ArtJvmtiEvent::kVmDeath)                               \
  fn(ThreadStart,             ArtJvmtiEvent::kThreadStart)                           \
  fn(ThreadEnd,               ArtJvmtiEvent::kThreadEnd)                             \
  fn(ClassFileLoadHook,       ArtJvmtiEvent::kClassFileLoadHookRetransformable)      \
  fn(ClassFileLoadHook,       ArtJvmtiEvent::kClassFileLoadHookNonRetransformable)   \
  fn(ClassLoad,               ArtJvmtiEvent::kClassLoad)                             \
  fn(ClassPrepare,            ArtJvmtiEvent::kClassPrepare)                          \
  fn(VMStart,                 ArtJvmtiEvent::kVmStart)                               \
  fn(Exception,               ArtJvmtiEvent::kException)                             \
  fn(ExceptionCatch,          ArtJvmtiEvent::kExceptionCatch)                        \
  fn(SingleStep,              ArtJvmtiEvent::kSingleStep)                            \
  fn(FramePop,                ArtJvmtiEvent::kFramePop)                              \
  fn(Breakpoint,              ArtJvmtiEvent::kBreakpoint)                            \
  fn(FieldAccess,             ArtJvmtiEvent::kFieldAccess)                           \
  fn(FieldModification,       ArtJvmtiEvent::kFieldModification)                     \
  fn(MethodEntry,             ArtJvmtiEvent::kMethodEntry)                           \
  fn(MethodExit,              ArtJvmtiEvent::kMethodExit)                            \
  fn(NativeMethodBind,        ArtJvmtiEvent::kNativeMethodBind)                      \
  fn(CompiledMethodLoad,      ArtJvmtiEvent::kCompiledMethodLoad)                    \
  fn(CompiledMethodUnload,    ArtJvmtiEvent::kCompiledMethodUnload)                  \
  fn(DynamicCodeGenerated,    ArtJvmtiEvent::kDynamicCodeGenerated)                  \
  fn(DataDumpRequest,         ArtJvmtiEvent::kDataDumpRequest)                       \
  fn(MonitorWait,             ArtJvmtiEvent::kMonitorWait)                           \
  fn(MonitorWaited,           ArtJvmtiEvent::kMonitorWaited)                         \
  fn(MonitorContendedEnter,   ArtJvmtiEvent::kMonitorContendedEnter)                 \
  fn(MonitorContendedEntered, ArtJvmtiEvent::kMonitorContendedEntered)               \
  fn(ResourceExhausted,       ArtJvmtiEvent::kResourceExhausted)                     \
  fn(GarbageCollectionStart,  ArtJvmtiEvent::kGarbageCollectionStart)                \
  fn(GarbageCollectionFinish, ArtJvmtiEvent::kGarbageCollectionFinish)               \
  fn(ObjectFree,              ArtJvmtiEvent::kObjectFree)                            \
  fn(VMObjectAlloc,           ArtJvmtiEvent::kVmObjectAlloc)

template <ArtJvmtiEvent kEvent>
struct EventFnType {
};

#define EVENT_FN_TYPE(name, enum_name)               \
template <>                                          \
struct EventFnType<enum_name> {                      \
  using type = decltype(jvmtiEventCallbacks().name); \
};

FORALL_EVENT_TYPES(EVENT_FN_TYPE)

#undef EVENT_FN_TYPE

template <ArtJvmtiEvent kEvent>
ALWAYS_INLINE inline typename EventFnType<kEvent>::type GetCallback(ArtJvmTiEnv* env);

#define GET_CALLBACK(name, enum_name)                                     \
template <>                                                               \
ALWAYS_INLINE inline EventFnType<enum_name>::type GetCallback<enum_name>( \
    ArtJvmTiEnv* env) {                                                   \
  if (env->event_callbacks == nullptr) {                                  \
    return nullptr;                                                       \
  }                                                                       \
  return env->event_callbacks->name;                                      \
}

FORALL_EVENT_TYPES(GET_CALLBACK)

#undef GET_CALLBACK

#undef FORALL_EVENT_TYPES

}  // namespace impl

// C++ does not allow partial template function specialization. The dispatch for our separated
// ClassFileLoadHook event types is the same, so use this helper for code deduplication.
// TODO Locking of some type!
template <ArtJvmtiEvent kEvent>
inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
                                                         JNIEnv* jnienv,
                                                         jclass class_being_redefined,
                                                         jobject loader,
                                                         const char* name,
                                                         jobject protection_domain,
                                                         jint class_data_len,
                                                         const unsigned char* class_data,
                                                         jint* new_class_data_len,
                                                         unsigned char** new_class_data) const {
  static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
                kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable, "Unsupported event");
  DCHECK(*new_class_data == nullptr);
  jint current_len = class_data_len;
  unsigned char* current_class_data = const_cast<unsigned char*>(class_data);
  ArtJvmTiEnv* last_env = nullptr;
  for (ArtJvmTiEnv* env : envs) {
    if (ShouldDispatch<kEvent>(env, thread)) {
      jint new_len = 0;
      unsigned char* new_data = nullptr;
      auto callback = impl::GetCallback<kEvent>(env);
      callback(env,
               jnienv,
               class_being_redefined,
               loader,
               name,
               protection_domain,
               current_len,
               current_class_data,
               &new_len,
               &new_data);
      if (new_data != nullptr && new_data != current_class_data) {
        // Destroy the data the last transformer made. We skip this if the previous state was the
        // initial one since we don't know here which jvmtiEnv allocated it.
        // NB Currently this doesn't matter since all allocations just go to malloc but in the
        // future we might have jvmtiEnv's keep track of their allocations for leak-checking.
        if (last_env != nullptr) {
          last_env->Deallocate(current_class_data);
        }
        last_env = env;
        current_class_data = new_data;
        current_len = new_len;
      }
    }
  }
  if (last_env != nullptr) {
    *new_class_data_len = current_len;
    *new_class_data = current_class_data;
  }
}

// Our goal for DispatchEvent: Do not allow implicit type conversion. Types of ...args must match
// exactly the argument types of the corresponding Jvmti kEvent function pointer.

template <ArtJvmtiEvent kEvent, typename ...Args>
inline void EventHandler::DispatchEvent(art::Thread* thread, Args... args) const {
  for (ArtJvmTiEnv* env : envs) {
    DispatchEvent<kEvent, Args...>(env, thread, args...);
  }
}

template <ArtJvmtiEvent kEvent, typename ...Args>
inline void EventHandler::DispatchEvent(ArtJvmTiEnv* env, art::Thread* thread, Args... args) const {
  using FnType = void(jvmtiEnv*, Args...);
  if (ShouldDispatch<kEvent>(env, thread)) {
    FnType* callback = impl::GetCallback<kEvent>(env);
    if (callback != nullptr) {
      (*callback)(env, args...);
    }
  }
}

// C++ does not allow partial template function specialization. The dispatch for our separated
// ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper.
// The following two DispatchEvent specializations dispatch to it.
template <>
inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
    art::Thread* thread,
    JNIEnv* jnienv,
    jclass class_being_redefined,
    jobject loader,
    const char* name,
    jobject protection_domain,
    jint class_data_len,
    const unsigned char* class_data,
    jint* new_class_data_len,
    unsigned char** new_class_data) const {
  return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
      thread,
      jnienv,
      class_being_redefined,
      loader,
      name,
      protection_domain,
      class_data_len,
      class_data,
      new_class_data_len,
      new_class_data);
}
template <>
inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
    art::Thread* thread,
    JNIEnv* jnienv,
    jclass class_being_redefined,
    jobject loader,
    const char* name,
    jobject protection_domain,
    jint class_data_len,
    const unsigned char* class_data,
    jint* new_class_data_len,
    unsigned char** new_class_data) const {
  return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
      thread,
      jnienv,
      class_being_redefined,
      loader,
      name,
      protection_domain,
      class_data_len,
      class_data,
      new_class_data_len,
      new_class_data);
}

template <ArtJvmtiEvent kEvent>
inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env,
                                         art::Thread* thread) {
  bool dispatch = env->event_masks.global_event_mask.Test(kEvent);

  if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(kEvent)) {
    EventMask* mask = env->event_masks.GetEventMaskOrNull(thread);
    dispatch = mask != nullptr && mask->Test(kEvent);
  }
  return dispatch;
}

inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
  bool union_value = false;
  for (const ArtJvmTiEnv* stored_env : envs) {
    union_value |= stored_env->event_masks.global_event_mask.Test(event);
    union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
    if (union_value) {
      break;
    }
  }
  global_mask.Set(event, union_value);
}

inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env,
                                           const jvmtiCapabilities& caps,
                                           bool added) {
  ArtJvmtiEvent event = added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
                              : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
  return caps.can_retransform_classes == 1 &&
      IsEventEnabledAnywhere(event) &&
      env->event_masks.IsEnabledAnywhere(event);
}

inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env,
                                                    const jvmtiCapabilities& caps,
                                                    bool added) {
  if (UNLIKELY(NeedsEventUpdate(env, caps, added))) {
    env->event_masks.HandleChangedCapabilities(caps, added);
    if (caps.can_retransform_classes == 1) {
      RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookRetransformable);
      RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
    }
  }
}

}  // namespace openjdkjvmti

#endif  // ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_
