view agent/src/oopUtil.cpp @ 37:80933f82c4c0

Bug 2365: Adapt to G1GC hook points of JDK-8049421 reviewed-by: yasuenag
author KUBOTA Yuji <kubota.yuji@lab.ntt.co.jp>
date Mon, 18 May 2015 00:36:35 +0900
parents 54cf38a69dca
children 0f15d6873c2d
line wrap: on
line source

/*!
 * \file oopUtil.cpp
 * \brief This file is used to getting information inner JVM.<br>
 * Copyright (C) 2011-2015 Nippon Telegraph and Telephone Corporation
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program 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 for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */

#include <jni.h>
#include <jvmti.h>

#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <pthread.h>
#include <sys/mman.h>
#include <unistd.h>

#include "oopUtil.hpp"
#include "util.hpp"
#include "bitMapMarker.hpp"
#include "snapShotMain.hpp"
#include "libmain.hpp"

/* Function define. */

/* Override functions. */

/* Macros for override function */

/*!
 * \brief Override function define macro for a function.
 */
#define DEFINE_OVERRIDE_FUNC_N(prefix, num) \
    extern "C" void *prefix##_override_func_##num;

/*!
 * \brief Override function define macro for one function.
 */
#define DEFINE_OVERRIDE_FUNC_1(prefix) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 0)

/*!
 * \brief Override function define macro for two function.
 */
#define DEFINE_OVERRIDE_FUNC_2(prefix) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 0) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 1)

/*!
 * \brief Override function define macro for three function.
 */
#define DEFINE_OVERRIDE_FUNC_3(prefix) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 0) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 1) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 2)

/*!
 * \brief Override function define macro for four function.
 */
#define DEFINE_OVERRIDE_FUNC_4(prefix) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 0) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 1) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 2) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 3)

/*!
 * \brief Override function define macro for eight function.
 */
#define DEFINE_OVERRIDE_FUNC_8(prefix) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 0) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 1) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 2) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 3) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 4) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 5) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 6) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 7)

/*!
 * \brief Override function define macro for nine function.
 */
#define DEFINE_OVERRIDE_FUNC_9(prefix) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 0) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 1) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 2) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 3) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 4) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 5) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 6) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 7) \
    DEFINE_OVERRIDE_FUNC_N(prefix, 8)

/*!
 * \brief Select override function information macro.
 */
#define SELECT_HOOK_FUNCS(prefix) \
    if (enableCR8049421) {                         \
        prefix##_hook = CR8049421_##prefix##_hook; \
    } else if (enableCR8027746) {                  \
        prefix##_hook = CR8027746_##prefix##_hook; \
    } else if (enableCR8000213) {                  \
        prefix##_hook = CR8000213_##prefix##_hook; \
    } else if (enableCR6964458) {                  \
        prefix##_hook = CR6964458_##prefix##_hook; \
    } else {                                       \
        prefix##_hook = default_##prefix##_hook;   \
    }

/* These functions is defined in override.S. */

/*!
 * \brief Override function for heap object on parallelGC.
 */
DEFINE_OVERRIDE_FUNC_4(par);

/*!
 * \brief Override function for heap object on parallelOldGC.
 */
DEFINE_OVERRIDE_FUNC_4(parOld);

/*!
 * \brief Override function for sweep at old gen on CMSGC.
 */
DEFINE_OVERRIDE_FUNC_1(cms_sweep);

/*!
 * \brief Override function for heap object at new gen on CMSGC.
 */
DEFINE_OVERRIDE_FUNC_4(cms_new);

/*!
 * \brief Override function for heap object on G1GC.
 */
DEFINE_OVERRIDE_FUNC_9(g1);
/*!
 * \brief Override function for cleanup and System.gc() event on G1GC.
 */
DEFINE_OVERRIDE_FUNC_3(g1Event);

/*!
 * \brief Override function for adjust klassOop.
 */
DEFINE_OVERRIDE_FUNC_8(adj);

/*!
 * \brief Override function for JVMTI function.
 */
DEFINE_OVERRIDE_FUNC_1(jvmti);

/*!
 * \brief Override function for inner GC function.
 */
DEFINE_OVERRIDE_FUNC_3(innerStart);

/*!
 * \brief Override function for WatcherThread.
 */
DEFINE_OVERRIDE_FUNC_1(watcherThread)


/* Variable. */

/* Define JVM paramter pointer variable for calling from external. */

/*!
 * \brief Value of "-XX:UseCompressedOops" or "-XX:UseCompressedClassPointers".
 */
bool isCOOP      = false;

/*!
 * \brief Value of "-XX:UseParallelGC".
 */
bool useParallel = false;

/*!
 * \brief Value of "-XX:UseParallelOldGC".
 */
bool useParOld   = false;

/*!
 * \brief Value of "-XX:UseConcMarkSweepGC".
 */
bool useCMS      = false;

/*!
 * \brief Value of "-XX:UseG1GC".
 */
bool useG1       = false;


/*!
 * \brief CMS collector state pointer.
 * \sa concurrentMarkSweepGeneration.hpp<br>
 *     at hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/<br>
 *     enum CollectorState
 */
int *CMS_collectorState  = NULL;

/* Define function pointer variable for calling from external. */

/*!
 * \brief Function pointer for "is_in_permanent".
 */
THeap_IsInPermanent is_in_permanent   = NULL;

/*!
 * \brief Pointer of "_collectedHeap" field in Universe.<br>
 *        Use to calling "is_in_permanent" function.
 */
void *collectedHeap                   = NULL;

/*!
 * \brief Function pointer for "JvmtiEnv::GetObjectSize".
 */
TJvmtiEnv_GetObjectSize getObjectSize = NULL;

/*!
 * \brief Function pointer for "java_lang_Class::as_klassOop".
 */
TJavaLangClass_AsKlassOop asKlassOop  = NULL;

/*!
 * \brief Function pointer for "instanceKlass::class_loader()".
 */
TGetClassLoader getClassLoaderForInstanceKlass = NULL;

/*!
 * \brief Function pointer for "objArrayKlass::class_loader()".
 */
TGetClassLoader getClassLoaderForObjArrayKlass = NULL;

/* Variable for inner class size. */

/*!
 * \brief Size of "oopDesc" class in JVM.
 */
uint64_t clsSizeOopDesc       = 0;

/*!
 * \brief Size of "klassOopDesc" class in JVM.
 */
uint64_t clsSizeKlassOop      = 0;

/*!
 * \brief Size of "narrowOop" class in JVM.
 */
uint64_t clsSizeNarrowOop     = 0;

/*!
 * \brief Size of "Klass" class in JVM.
 */
uint64_t clsSizeKlass         = 0;

/*!
 * \brief Size of "instanceKlass" class in JVM.
 */
uint64_t clsSizeInstanceKlass = 0;

/*!
 * \brief Size of "arrayOopDesc" class in JVM.
 */
uint64_t clsSizeArrayOopDesc  = 0;

/* Variable for inner class field offset. */

/*!
 * \brief Offset of "oopDesc" class's "_metadata._klass" field.
 *        This field is stored class object when JVM don't using COOP.
 */
off_t ofsKlassAtOop     = -1;

/*!
 * \brief Offset of "oopDesc" class's "_metadata._compressed_klass" field.
 *        This field is stored class object when JVM is using COOP.
 */
off_t ofsCoopKlassAtOop = -1;

/*!
 * \brief Offset of "oopDesc" class's "_mark" field.
 *        This field is stored bit flags of lock information.
 */
off_t ofsMarkAtOop      = -1;

/*!
 * \brief Offset of "Klass" class's "_name" field.
 *        This field is stored symbol object that designed class name.
 */
off_t ofsNameAtKlass    = -1;

/*!
 * \brief Offset of "Symbol" class's "_length" field.
 *        This field is stored string size of class name.
 */
off_t ofsLengthAtSymbol = -1;

/*!
 * \brief Offset of "Symbol" class's "_body" field.
 *        This field is stored string of class name.
 */
off_t ofsBodyAtSymbol   = -1;

/*!
 * \brief Offset of "instanceKlass" class's "_vtable_len" field.
 *        This field is stored vtable size.
 */
off_t ofsVTableSizeAtInsKlass         = -1;

/*!
 * \brief Offset of "instanceKlass" class's "_itable_len" field.
 *        This field is stored itable size.
 */
off_t ofsITableSizeAtInsKlass         = -1;

/*!
 * \brief Offset of "instanceKlass" class's "_static_field_size" field.
 *        This field is stored static field size.
 */
off_t ofsStaticFieldSizeAtInsKlass    = -1;

/*!
 * \brief Offset of "instanceKlass" class's "_nonstatic_oop_map_size" field.
 *        This field is stored static field size.
 */
off_t ofsNonstatiOopMapSizeAtInsKlass = -1;

/*!
 * \brief Offset of "oopDesc" class's "klass_offset_in_bytes" field.
 *        This field is stored static field size.
 */
off_t ofsKlassOffsetInBytesAtOopDesc   = -1;

/* Variable for environment information. */

/*!
* \brief Pointer of COOP base address.
 */
ptrdiff_t narrowOffsetBase = 0;

/*!
* \brief Value of COOP shift bits.
 */
int narrowOffsetShift     = 0;

/*!
* \brief Pointer of Klass COOP base address.
 */
ptrdiff_t narrowKlassOffsetBase = 0;

/*!
* \brief Value of Klass COOP shift bits.
 */
int narrowKlassOffsetShift     = 0;

/*!
 * \brief Lock bit mask.<br>
 *        Value of "markOopDesc" class's "lock_mask_in_place" constant value.
 */
uint64_t lockMaskInPlaceMarkOop = 0;

/* Variable for CMS marking bitmap. */

/*!
 * \brief Pointer of CMS marking bitmap start word.
 */
void *cmsBitMap_startWord    = NULL;
/*!
 * \brief Value of CMS bitmap shifter.
 */
int cmsBitMap_shifter       = 0;
/*!
 * \brief Pointer to CMS Marking bitmap start memory address.
 */
size_t *cmsBitMap_startAddr  = NULL;

/*!
 * \brief Size of integer(regular integer register) on now environment.<br>
 *        BitsPerWord is used by CMS GC mark bitmap.<br>
 *        This value is default. At "setupForCMS", read from VMIntConstant.
 */
int32_t HeapWordSize = 
#ifdef __LP64__
    8
#else
    4
#endif
;

/*!
 * \brief Number of bit to need expressing integer size of "HeapWordSize".
 *        HeapWordSize = 2 ^ LogHeapWordSize.<br>
 *        BitsPerWord is used by CMS GC mark bitmap.<br>
 *        This value is default. At "setupForCMS", read from VMIntConstant.
 */
int32_t LogHeapWordSize = 
#ifdef __LP64__
    3
#else
    2
#endif
;

/*!
 * \brief It's integer's number to need for expressing 64bit integer
 *        on now environment.<br>
 *        BitsPerWord is used by CMS GC mark bitmap.<br>
 *        This value is default. At "setupForCMS", read from JVM symbol.
 */
int HeapWordsPerLong = 
#ifdef __LP64__
    1
#else
    2
#endif
;

/*!
 * \brief Number of bit to need expressing a integer register.<br>
 *        LogBitsPerWord = 2 ^ LogBitsPerWord.<br>
 *        BitsPerWord is used by CMS GC mark bitmap.<br>
 *        This value is default. At "setupForCMS", read from JVM symbol.
 */
int LogBitsPerWord = 
#ifdef __LP64__
    6
#else
    5
#endif
;

/*!
 * \brief Number of bit to expressable max integer by single register
 *        on now environment.<br>
 *        LogBitsPerWord = sizeof(long) * 8.<br>
 *        BitsPerWord is used by CMS GC mark bitmap.<br>
 *        This value is default. At "setupForCMS", read from JVM symbol.
 */
int BitsPerWord = 
#ifdef __LP64__
    64
#else
    32
#endif
;

/*!
 * \brief Mask bit data of BitsPerWord.<br>
 *        Used by CMSGC("isMarkedObject") process.
 */
int BitsPerWordMask = 0;

/*!
 * \brief JVM safepoint state pointer.
 */
int *safePointState = NULL;

/* Variable for class object. */

/*!
 * \brief Symbol finder object about "libjvm.so" shared library.
 */
TSymbolFinder    *symFinder = NULL;

/*!
 * \brief JVM inner structure scanner.
 */
TVMStructScanner *vmScanner = NULL;

/*!
 * \brief Bitmap object for G1 GC.
 */
TBitMapMarker    *checkObjectMap = NULL;


/* Variable for override information. */

/*!
 * \brief Pointer of hook information on parallelGC for default.
 */
THookFunctionInfo default_par_hook[] = {
    HOOK_FUNC("_ZTV13instanceKlass",
        "_ZN13instanceKlass19oop_follow_contentsEP7oopDesc",
        &par_override_func_0, NULL),
    HOOK_FUNC("_ZTV13objArrayKlass",
        "_ZN13objArrayKlass19oop_follow_contentsEP7oopDesc",
        &par_override_func_1, NULL),
    HOOK_FUNC("_ZTV14typeArrayKlass",
        "_ZN14typeArrayKlass19oop_follow_contentsEP7oopDesc",
        &par_override_func_2, NULL),
    HOOK_FUNC("_ZTV16instanceRefKlass",
        "_ZN16instanceRefKlass19oop_follow_contentsEP7oopDesc",
        &par_override_func_3, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on parallelGC for after CR6964458.
 */
THookFunctionInfo CR6964458_par_hook[] = {
    HOOK_FUNC("_ZTV13InstanceKlass",
        "_ZN13InstanceKlass19oop_follow_contentsEP7oopDesc",
        &par_override_func_0, NULL),
    HOOK_FUNC("_ZTV13objArrayKlass",
        "_ZN13objArrayKlass19oop_follow_contentsEP7oopDesc",
        &par_override_func_1, NULL),
    HOOK_FUNC("_ZTV14typeArrayKlass",
        "_ZN14typeArrayKlass19oop_follow_contentsEP7oopDesc",
        &par_override_func_2, NULL),
    HOOK_FUNC("_ZTV16InstanceRefKlass",
        "_ZN16InstanceRefKlass19oop_follow_contentsEP7oopDesc",
        &par_override_func_3, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on parallelGC for after CR8000213.
 */
THookFunctionInfo CR8000213_par_hook[] = {
    HOOK_FUNC("_ZTV13InstanceKlass",
        "_ZN13InstanceKlass19oop_follow_contentsEP7oopDesc",
        &par_override_func_0, NULL),
    HOOK_FUNC("_ZTV13ObjArrayKlass",
        "_ZN13ObjArrayKlass19oop_follow_contentsEP7oopDesc",
        &par_override_func_1, NULL),
    HOOK_FUNC("_ZTV14TypeArrayKlass",
        "_ZN14TypeArrayKlass19oop_follow_contentsEP7oopDesc",
        &par_override_func_2, NULL),
    HOOK_FUNC("_ZTV16InstanceRefKlass",
        "_ZN16InstanceRefKlass19oop_follow_contentsEP7oopDesc",
        &par_override_func_3, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointers of hook information on parallelGC for several CRs.<br>
 *        These CRs have no impact on parallelGC, so refer to the last.
 */
#define CR8027746_par_hook CR8000213_par_hook
#define CR8049421_par_hook CR8000213_par_hook

/*!
 * \brief Pointer of hook information on parallelGC.
 */
THookFunctionInfo *par_hook = NULL;

/*!
 * \brief Pointer of hook information on parallelOldGC for default.
 */
THookFunctionInfo default_parOld_hook[] = {
    HOOK_FUNC("_ZTV13instanceKlass",
        "_ZN13instanceKlass19oop_follow_contents"
        "EP20ParCompactionManagerP7oopDesc",
        &parOld_override_func_0, NULL),
    HOOK_FUNC("_ZTV13objArrayKlass",
        "_ZN13objArrayKlass19oop_follow_contents"
        "EP20ParCompactionManagerP7oopDesc",
        &parOld_override_func_1, NULL),
    HOOK_FUNC("_ZTV14typeArrayKlass",
        "_ZN14typeArrayKlass19oop_follow_contents"
        "EP20ParCompactionManagerP7oopDesc",
        &parOld_override_func_2, NULL),
    HOOK_FUNC("_ZTV16instanceRefKlass",
        "_ZN16instanceRefKlass19oop_follow_contents"
        "EP20ParCompactionManagerP7oopDesc",
        &parOld_override_func_3, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on parallelOldGC for after CR6964458.
 */
THookFunctionInfo CR6964458_parOld_hook[] = {
    HOOK_FUNC("_ZTV13InstanceKlass",
        "_ZN13InstanceKlass19oop_follow_contents"
        "EP20ParCompactionManagerP7oopDesc",
        &parOld_override_func_0, NULL),
    HOOK_FUNC("_ZTV13objArrayKlass",
        "_ZN13objArrayKlass19oop_follow_contents"
        "EP20ParCompactionManagerP7oopDesc",
        &parOld_override_func_1, NULL),
    HOOK_FUNC("_ZTV14typeArrayKlass",
        "_ZN14typeArrayKlass19oop_follow_contents"
        "EP20ParCompactionManagerP7oopDesc",
        &parOld_override_func_2, NULL),
    HOOK_FUNC("_ZTV16InstanceRefKlass",
        "_ZN16InstanceRefKlass19oop_follow_contents"
        "EP20ParCompactionManagerP7oopDesc",
        &parOld_override_func_3, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on parallelOldGC for after CR8000213.
 */
THookFunctionInfo CR8000213_parOld_hook[] = {
    HOOK_FUNC("_ZTV13InstanceKlass",
        "_ZN13InstanceKlass19oop_follow_contents"
        "EP20ParCompactionManagerP7oopDesc",
        &parOld_override_func_0, NULL),
    HOOK_FUNC("_ZTV13ObjArrayKlass",
        "_ZN13ObjArrayKlass19oop_follow_contents"
        "EP20ParCompactionManagerP7oopDesc",
        &parOld_override_func_1, NULL),
    HOOK_FUNC("_ZTV14TypeArrayKlass",
        "_ZN14TypeArrayKlass19oop_follow_contents"
        "EP20ParCompactionManagerP7oopDesc",
        &parOld_override_func_2, NULL),
    HOOK_FUNC("_ZTV16InstanceRefKlass",
        "_ZN16InstanceRefKlass19oop_follow_contents"
        "EP20ParCompactionManagerP7oopDesc",
        &parOld_override_func_3, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointers of hook information on parallelOldGC for several CRs.<br>
 *        These CRs have no impact on parallelOldGC, so refer to the last.
 */
#define CR8027746_parOld_hook CR8000213_parOld_hook
#define CR8049421_parOld_hook CR8000213_parOld_hook

/*!
 * \brief Pointer of hook information on parallelGC.
 */
THookFunctionInfo *parOld_hook = NULL;

/*!
 * \brief Pointer of hook information on CMSGC for default.
 */
THookFunctionInfo default_cms_sweep_hook[] = {
    HOOK_FUNC("_ZTV12SweepClosure",
        "_ZN12SweepClosure14do_blk_carefulEP8HeapWord",
        &cms_sweep_override_func_0, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on CMSGC.
 */
THookFunctionInfo *cms_sweep_hook = default_cms_sweep_hook;

/*!
 * \brief Pointer of hook information on CMSGC for default.
 */
THookFunctionInfo default_cms_new_hook[] = {
    HOOK_FUNC("_ZTV13instanceKlass",
        "_ZN13instanceKlass18oop_oop_iterate_nv"
        "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
        &cms_new_override_func_0, NULL),
    HOOK_FUNC("_ZTV13objArrayKlass",
        "_ZN13objArrayKlass18oop_oop_iterate_nv"
        "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
        &cms_new_override_func_1, NULL),
    HOOK_FUNC("_ZTV14typeArrayKlass",
        "_ZN14typeArrayKlass15oop_oop_iterate"
        "EP7oopDescP10OopClosure",
        &cms_new_override_func_2, NULL),
    HOOK_FUNC("_ZTV16instanceRefKlass",
        "_ZN16instanceRefKlass18oop_oop_iterate_nv"
        "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
        &cms_new_override_func_3, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on CMSGC for after CR6964458.
 */
THookFunctionInfo CR6964458_cms_new_hook[] = {
    HOOK_FUNC("_ZTV13InstanceKlass",
        "_ZN13InstanceKlass18oop_oop_iterate_nv"
        "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
        &cms_new_override_func_0, NULL),
    HOOK_FUNC("_ZTV13objArrayKlass",
        "_ZN13objArrayKlass18oop_oop_iterate_nv"
        "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
        &cms_new_override_func_1, NULL),
    HOOK_FUNC("_ZTV14typeArrayKlass",
        "_ZN14typeArrayKlass15oop_oop_iterate"
        "EP7oopDescP18ExtendedOopClosure",
        &cms_new_override_func_2, NULL),
    HOOK_FUNC("_ZTV16InstanceRefKlass",
        "_ZN16InstanceRefKlass18oop_oop_iterate_nv"
        "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
        &cms_new_override_func_3, NULL),
    HOOK_FUNC_END
};

/*!
* \brief Pointer of hook information on CMSGC for after CR8000213.
*/
THookFunctionInfo CR8000213_cms_new_hook[] = {
    HOOK_FUNC("_ZTV13InstanceKlass",
        "_ZN13InstanceKlass18oop_oop_iterate_nv"
        "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
        &cms_new_override_func_0, NULL),
    HOOK_FUNC("_ZTV13ObjArrayKlass",
        "_ZN13ObjArrayKlass18oop_oop_iterate_nv"
        "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
        &cms_new_override_func_1, NULL),
    HOOK_FUNC("_ZTV14TypeArrayKlass",
        "_ZN14TypeArrayKlass15oop_oop_iterate"
        "EP7oopDescP18ExtendedOopClosure",
        &cms_new_override_func_2, NULL),
    HOOK_FUNC("_ZTV16InstanceRefKlass",
        "_ZN16InstanceRefKlass18oop_oop_iterate_nv"
        "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
        &cms_new_override_func_3, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointers of hook information on CMSGC for several CRs.<br>
 *        These CRs have no impact on CMSGC, so refer to the last.
*/
#define CR8027746_cms_new_hook CR8000213_cms_new_hook
#define CR8049421_cms_new_hook CR8000213_cms_new_hook

/*!
 * \brief Pointer of hook information on parallelGC.
 */
THookFunctionInfo *cms_new_hook = NULL;

/*!
 * \brief Pointer of hook information on G1GC for default.
 */
THookFunctionInfo default_g1_hook[] = {
    HOOK_FUNC("_ZTV16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE",
        "_ZN16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE6do_oopEPP7oopDesc",
        &g1_override_func_0, NULL),
    HOOK_FUNC("_ZTV16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE",
        "_ZN16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE6do_oopEPj",
        &g1_override_func_1, NULL),
    HOOK_FUNC("_ZTV13instanceKlass",
        "_ZN13instanceKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
        &g1_override_func_2, NULL),
    HOOK_FUNC("_ZTV13objArrayKlass",
        "_ZN13objArrayKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
        &g1_override_func_3, NULL),
    HOOK_FUNC("_ZTV16instanceRefKlass",
        "_ZN16instanceRefKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
        &g1_override_func_4, NULL),
    HOOK_FUNC("_ZTV13instanceKlass",
              "_ZN13instanceKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
        &g1_override_func_5, NULL),
    HOOK_FUNC("_ZTV13objArrayKlass",
        "_ZN13objArrayKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
        &g1_override_func_6, NULL),
    HOOK_FUNC("_ZTV14typeArrayKlass",
        "_ZN14typeArrayKlass15oop_oop_iterateEP7oopDescP10OopClosure",
        &g1_override_func_7, NULL),
    HOOK_FUNC("_ZTV16instanceRefKlass",
        "_ZN16instanceRefKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
        &g1_override_func_8, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on G1GC for after CR6964458.
 */
THookFunctionInfo CR6964458_g1_hook[] = {
    HOOK_FUNC("_ZTV16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE",
        "_ZN16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE6do_oopEPP7oopDesc",
        &g1_override_func_0, NULL),
    HOOK_FUNC("_ZTV16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE",
        "_ZN16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE6do_oopEPj",
        &g1_override_func_1, NULL),
    HOOK_FUNC("_ZTV13InstanceKlass",
        "_ZN13InstanceKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
        &g1_override_func_2, NULL),
    HOOK_FUNC("_ZTV13objArrayKlass",
        "_ZN13objArrayKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
        &g1_override_func_3, NULL),
    HOOK_FUNC("_ZTV16InstanceRefKlass",
        "_ZN16InstanceRefKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
        &g1_override_func_4, NULL),
    HOOK_FUNC("_ZTV13InstanceKlass",
        "_ZN13InstanceKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
        &g1_override_func_5, NULL),
    HOOK_FUNC("_ZTV13objArrayKlass",
        "_ZN13objArrayKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
        &g1_override_func_6, NULL),
    HOOK_FUNC("_ZTV14typeArrayKlass",
        "_ZN14typeArrayKlass15oop_oop_iterateEP7oopDescP18ExtendedOopClosure",
        &g1_override_func_7, NULL),
    HOOK_FUNC("_ZTV16InstanceRefKlass",
        "_ZN16InstanceRefKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
        &g1_override_func_8, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on G1GC for after CR8000213.
 */
THookFunctionInfo CR8000213_g1_hook[] = {
    HOOK_FUNC("_ZTV16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE",
        "_ZN16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE6do_oopEPP7oopDesc",
        &g1_override_func_0, NULL),
    HOOK_FUNC("_ZTV16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE",
        "_ZN16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE6do_oopEPj",
        &g1_override_func_1, NULL),
    HOOK_FUNC("_ZTV13InstanceKlass",
        "_ZN13InstanceKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
        &g1_override_func_2, NULL),
    HOOK_FUNC("_ZTV13ObjArrayKlass",
        "_ZN13ObjArrayKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
        &g1_override_func_3, NULL),
    HOOK_FUNC("_ZTV16InstanceRefKlass",
        "_ZN16InstanceRefKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
        &g1_override_func_4, NULL),
    HOOK_FUNC("_ZTV13InstanceKlass",
        "_ZN13InstanceKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
        &g1_override_func_5, NULL),
    HOOK_FUNC("_ZTV13ObjArrayKlass",
        "_ZN13ObjArrayKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
        &g1_override_func_6, NULL),
    HOOK_FUNC("_ZTV14TypeArrayKlass",
        "_ZN14TypeArrayKlass15oop_oop_iterateEP7oopDescP18ExtendedOopClosure",
        &g1_override_func_7, NULL),
    HOOK_FUNC("_ZTV16InstanceRefKlass",
        "_ZN16InstanceRefKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
        &g1_override_func_8, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on G1GC for after CR8027746.
 */
THookFunctionInfo CR8027746_g1_hook[] = {
    HOOK_FUNC("_ZTV16G1ParCopyClosureIL9G1Barrier0ELb1EE",
        "_ZN16G1ParCopyClosureIL9G1Barrier0ELb1EE6do_oopEPP7oopDesc",
        &g1_override_func_0, NULL),
    HOOK_FUNC("_ZTV16G1ParCopyClosureIL9G1Barrier0ELb1EE",
        "_ZN16G1ParCopyClosureIL9G1Barrier0ELb1EE6do_oopEPj",
        &g1_override_func_1, NULL),
    HOOK_FUNC("_ZTV13InstanceKlass",
        "_ZN13InstanceKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
        &g1_override_func_2, NULL),
    HOOK_FUNC("_ZTV13ObjArrayKlass",
        "_ZN13ObjArrayKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
        &g1_override_func_3, NULL),
    HOOK_FUNC("_ZTV16InstanceRefKlass",
        "_ZN16InstanceRefKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
        &g1_override_func_4, NULL),
    HOOK_FUNC("_ZTV13InstanceKlass",
        "_ZN13InstanceKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
        &g1_override_func_5, NULL),
    HOOK_FUNC("_ZTV13ObjArrayKlass",
        "_ZN13ObjArrayKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
        &g1_override_func_6, NULL),
    HOOK_FUNC("_ZTV14TypeArrayKlass",
        "_ZN14TypeArrayKlass15oop_oop_iterateEP7oopDescP18ExtendedOopClosure",
        &g1_override_func_7, NULL),
    HOOK_FUNC("_ZTV16InstanceRefKlass",
        "_ZN16InstanceRefKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
        &g1_override_func_8, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on G1GC for after JDK-8049421.
 */
THookFunctionInfo CR8049421_g1_hook[] = {
    HOOK_FUNC("_ZTV16G1ParCopyClosureIL9G1Barrier0EL6G1Mark1EE",
        "_ZN16G1ParCopyClosureIL9G1Barrier0EL6G1Mark1EE6do_oopEPP7oopDesc",
        &g1_override_func_0, NULL),
    HOOK_FUNC("_ZTV16G1ParCopyClosureIL9G1Barrier0EL6G1Mark1EE",
        "_ZN16G1ParCopyClosureIL9G1Barrier0EL6G1Mark1EE6do_oopEPj",
        &g1_override_func_1, NULL),
    HOOK_FUNC("_ZTV13InstanceKlass",
        "_ZN13InstanceKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
        &g1_override_func_2, NULL),
    HOOK_FUNC("_ZTV13ObjArrayKlass",
        "_ZN13ObjArrayKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
        &g1_override_func_3, NULL),
    HOOK_FUNC("_ZTV16InstanceRefKlass",
        "_ZN16InstanceRefKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
        &g1_override_func_4, NULL),
    HOOK_FUNC("_ZTV13InstanceKlass",
        "_ZN13InstanceKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
        &g1_override_func_5, NULL),
    HOOK_FUNC("_ZTV13ObjArrayKlass",
        "_ZN13ObjArrayKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
        &g1_override_func_6, NULL),
    HOOK_FUNC("_ZTV14TypeArrayKlass",
        "_ZN14TypeArrayKlass15oop_oop_iterateEP7oopDescP18ExtendedOopClosure",
        &g1_override_func_7, NULL),
    HOOK_FUNC("_ZTV16InstanceRefKlass",
        "_ZN16InstanceRefKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
        &g1_override_func_8, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on parallelGC.
 */
THookFunctionInfo *g1_hook = NULL;

/*!
 * \brief Pointer of hook information on G1GC cleanup event for default.
 */
THookFunctionInfo default_g1Event_hook[] = {
    HOOK_FUNC("_ZTV9CMCleanUp",
        "_ZN9CMCleanUp7do_voidEv",
        &g1Event_override_func_0, NULL),
    HOOK_FUNC("_ZTV15G1CollectedHeap",
        "_ZN15G1CollectedHeap11gc_prologueEb",
        &g1Event_override_func_1, NULL),
    HOOK_FUNC("_ZTV15G1CollectedHeap",
        "_ZN15G1CollectedHeap11gc_epilogueEb",
        &g1Event_override_func_2, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on G1GC cleanup event.
 */
THookFunctionInfo *g1Event_hook = default_g1Event_hook;

/*!
 * \brief Pointer of hook change and adjust oop with GC for default.
 */
THookFunctionInfo default_adj_hook[] = {
    HOOK_FUNC("_ZTV18instanceKlassKlass",
        "_ZN18instanceKlassKlass19oop_adjust_pointersEP7oopDesc",
        &adj_override_func_0, NULL),
    HOOK_FUNC("_ZTV18objArrayKlassKlass",
        "_ZN18objArrayKlassKlass19oop_adjust_pointersEP7oopDesc",
        &adj_override_func_1, NULL),
    HOOK_FUNC("_ZTV15arrayKlassKlass",
        "_ZN15arrayKlassKlass19oop_adjust_pointersEP7oopDesc",
        &adj_override_func_2, NULL),
    
    HOOK_FUNC("_ZTV20MoveAndUpdateClosure",
    #ifdef __LP64__
        "_ZN20MoveAndUpdateClosure7do_addrEP8HeapWordm",
    #else
        "_ZN20MoveAndUpdateClosure7do_addrEP8HeapWordj",
    #endif
        &adj_override_func_3, NULL),
    HOOK_FUNC("_ZTV17UpdateOnlyClosure",
    #ifdef __LP64__
        "_ZN17UpdateOnlyClosure7do_addrEP8HeapWordm",
    #else
        "_ZN17UpdateOnlyClosure7do_addrEP8HeapWordj",
    #endif
        &adj_override_func_4, NULL),
    
    HOOK_FUNC("_ZTV18instanceKlassKlass",
        "_ZN18instanceKlassKlass19oop_update_pointers"
        "EP20ParCompactionManagerP7oopDesc",
        &adj_override_func_5, NULL),
    HOOK_FUNC("_ZTV18objArrayKlassKlass",
        "_ZN18objArrayKlassKlass19oop_update_pointers"
        "EP20ParCompactionManagerP7oopDesc",
        &adj_override_func_6, NULL),
    HOOK_FUNC("_ZTV15arrayKlassKlass",
        "_ZN15arrayKlassKlass19oop_update_pointers"
        "EP20ParCompactionManagerP7oopDesc",
        &adj_override_func_7, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook change and adjust oop with GC.
 */
THookFunctionInfo *adj_hook = default_adj_hook;

/*!
 * \brief Pointer of hook oop iterate with JVMTI HeapOverIterate for default.
 */
THookFunctionInfo default_jvmti_hook[] = {
    HOOK_FUNC("_ZTV28IterateOverHeapObjectClosure",
        "_ZN28IterateOverHeapObjectClosure9do_objectEP7oopDesc",
        &jvmti_override_func_0, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook oop iterate with JVMTI HeapOverIterate.
 */
THookFunctionInfo *jvmti_hook = default_jvmti_hook;

/*!
 * \brief Pointer of hook inner GC function for default.
 */
THookFunctionInfo default_innerStart_hook[] = {
    HOOK_FUNC("_ZTV20ParallelScavengeHeap",
        "_ZN20ParallelScavengeHeap31accumulate_statistics_all_tlabsEv",
        &innerStart_override_func_0, NULL),
    HOOK_FUNC("_ZTV13CollectedHeap",
        "_ZN13CollectedHeap31accumulate_statistics_all_tlabsEv",
        &innerStart_override_func_1, NULL),
    HOOK_FUNC("_ZTV16GenCollectedHeap",
        "_ZN16GenCollectedHeap11gc_prologueEb",
        &innerStart_override_func_2, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook inner GC function.
 */
THookFunctionInfo *innerStart_hook = default_innerStart_hook;

/*!
 * \brief Pointer of WatcherThread hook.
 */
THookFunctionInfo default_watcherThread_hook[] = {
  HOOK_FUNC("_ZTV13WatcherThread",
    "_ZN13WatcherThread3runEv",
    &watcherThread_override_func_0, (void *)callbackForWatcherThreadRun),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook WatcherThread.
 */
THookFunctionInfo *watcherThread_hook = default_watcherThread_hook;


/* Event callback for outter. */

/*!
 * \brief Callback function for general GC function hooking.
 */
THeapObjectCallback gcCallbackFunc = NULL;

/*!
 * \brief Callback function for CMSGC function hooking.
 */
THeapObjectCallback cmsCallbackFunc = NULL;

/*!
 * \brief Callback function for JVMTI iterate hooking.
 */
THeapObjectCallback jvmtiIteCallbackFunc = NULL;

/*!
 * \brief Callback function for adjust oop function hooking.
 */
TKlassAdjustCallback adjustCallbackFunc = NULL;

/*!
 * \brief Callback function for finished G1GC.
 */
TCommonCallback g1FinishCallbackFunc = NULL;

/*!
 * \brief Callback function for interrupt GC.
 */
TCommonCallback gcInterruptCallbackFunc = NULL;

/* Variable for inner work. */

/*!
 * \brief flag of snapshot with CMS phase.
 */
bool needSnapShotByCMSPhase = false;

/*!
 * \brief flag of GC hooking enable.
 */
bool isEnableGCHooking = false;

/*!
 * \brief flag of JVMTI hooking enable.
 */
bool isEnableJvmtiHooking = false;

/*!
 * \brief Pthread key to store old klassOop.
 */
pthread_key_t oldKlassOopKey;

/*!
 * \brief flag of inner GC function is called many times.
 */
bool isInvokeGCManyTimes = false;

/* Variable for hotspot version. */

/*!
 * \brief JVM version.
 */
unsigned int hotSpotVersion = 0U;

/*!
 * \brief Flag of JVM is applyed CR#7017732.<br>
 *        Decision for 7017732: 
 *        move static fields into Class to prepare for perm gen removal.
 * \sa http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7017732
 * \sa http://hg.openjdk.java.net/hsx/hotspot-rt-gate/hotspot/rev/c7f3d0b4570f
 */
bool enableCR7017732 = false;

/*!
 * \brief Flag of JVM is applyed CR#6964458.<br>
 *        Decision for 6964458:
 *        Reimplement class meta-data storage to use native memory.
 *        (PermGen Removal)
 * \sa http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6964458
 * \sa http://hg.openjdk.java.net/hsx/hotspot-rt-gate/hotspot/rev/da91efe96a93
 */
bool enableCR6964458 = false;

/*!
 * \brief Flag of JVM is applyed CR#8000213.<br>
 *        Decision for CR8000213:
 *        NPG: Should have renamed arrayKlass and typeArrayKlass.
 * \sa http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8000213
 * \sa http://hg.openjdk.java.net/hsx/hotspot-rt/hotspot/rev/d8ce2825b193
 */
bool enableCR8000213 = false;

/*!
 * \brief Flag of JVM is applyed JDK-8027746.<br>
 *        Remove do_gen_barrier template parameter in G1ParCopyClosure
 * \sa https://bugs.openjdk.java.net/browse/JDK-8027746
 * \sa http://hg.openjdk.java.net/jdk9/jdk9/hotspot/rev/c685ef164975
 */
bool enableCR8027746 = false;

/*!
 * \brief Flag of JVM is applyed CR#8004883.<br>
 *        Decision for CR8004883:
 *        8004883: NPG: clean up anonymous class fix
 * \sa http://bugs.sun.com/view_bug.do?bug_id=8004883
 * \sa http://hg.openjdk.java.net/hsx/hotspot-gc/hotspot/rev/30866cd626b0
 */
bool enableCR8004883 = false;

/*!
 * \brief Flag of JVM is applyed CR#8003424.<br>
 *        Decision for CR8003424:
 *        8003424: Enable Class Data Sharing for CompressedOops
 * \sa http://bugs.sun.com/view_bug.do?bug_id=8003424
 * \sa http://hg.openjdk.java.net/hsx/hotspot-rt/hotspot/rev/740e263c80c6
 */
bool enableCR8003424 = false;

/*!
 * \brief Flag of JVM is applyed CR#8015107.<br>
 *        Decision for CR8015107:
 *        8015107: NPG: Use consistent naming for metaspace concepts
 * \sa https://bugs.openjdk.java.net/browse/JDK-8015107
 */
bool enableCR8015107 = false;

/*!
 * \brief Flag of JVM is applyed JDK-8049421.<br>
 *        G1 Class Unloading after completing a concurrent mark cycle
 * \sa https://bugs.openjdk.java.net/browse/JDK-8049421
 * \sa http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/rev/2c6ef90f030a
 */
bool enableCR8049421 = false;

/* Variable for hotspot version. */

/*!
 * \brief Flag of called parallel gc on using CMS gc.
 */
bool isInvokedParallelGC = false;

/*!
 * \brief VTable list which should be hooked.
 */
void *VTableForTypeArrayOopClosure[2] __attribute__((aligned(16)));


/* Macro. */

/* Symbol macro. */

/*!
 * \brief String of symbol which is "is_in_permanent" function on parallel GC.
 */
#define IS_IN_PERM_ON_PARALLEL_GC_SYMBOL \
    "_ZNK20ParallelScavengeHeap15is_in_permanentEPKv"

/*!
 * \brief String of symbol which is "is_in_permanent" function on other GC.
 */
#define IS_IN_PERM_ON_OTHER_GC_SYMBOL \
    "_ZNK10SharedHeap15is_in_permanentEPKv"

/*!
 * \brief Symbol of "JvmtiEnv::GetObjectSize" macro.
 */
#ifdef __x86_64__
    #define SYMBOL_GETOBJCTSIZE "_ZN8JvmtiEnv13GetObjectSizeEP8_jobjectPl"
#else
    #define SYMBOL_GETOBJCTSIZE "_ZN8JvmtiEnv13GetObjectSizeEP8_jobjectPx"
#endif

/*!
 * \brief String of symbol which is "java.lang.Class.as_klassOop" function.
 */
#define AS_KLASSOOP_SYMBOL "_ZN15java_lang_Class11as_klassOopEP7oopDesc"

/*!
 * \brief String of symbol which is "java.lang.Class.as_klass" function.<br />
 *        This function is for after CR6964458.
 */
#define AS_KLASS_SYMBOL "_ZN15java_lang_Class8as_KlassEP7oopDesc"

/*!
 * \brief String of symbol which is safepoint state variable.
 */
#define SAFEPOINT_STATE_SYMBOL "_ZN20SafepointSynchronize6_stateE"

/*!
 * \brief String of symbol which is function get class loader for instance.
 */
#define GET_CLSLOADER_FOR_INSTANCE_SYMBOL "_ZNK13instanceKlass12class_loaderEv"

/*!
 * \brief String of symbol which is function get class loader for instance
 *        after CR#8004883.
 */
#define CR8004883_GET_CLSLOADER_FOR_INSTANCE_SYMBOL "_ZNK13InstanceKlass12klass_holderEv"

/*!
 * \brief String of symbol which is function get class loader for object array.
 */
#define GET_CLSLOADER_FOR_OBJARY_SYMBOL "_ZNK13objArrayKlass12class_loaderEv"

/*!
 * \brief String of symbol which is function get class loader for object array
 *        after CR#8004883.
 */
#define CR8004883_GET_CLSLOADER_FOR_OBJARY_SYMBOL "_ZNK5Klass12klass_holderEv"

/* Other macro. */

/*!
 * \brief Calculate pointer align macro.
 */
#define ALIGN_POINTER_OFFSET(size) \
    (ALIGN_SIZE_UP((size), HeapWordsPerLong))

/*!
 * \brief Header macro for array array class. Chars of "[[".
 */
#define HEADER_KLASS_ARRAY_ARRAY     0x5b5b

#ifdef WORDS_BIGENDIAN
    
    /*!
     * \brief Header macro for object array class. Chars of "[L".
     */
    #define HEADER_KLASS_OBJ_ARRAY   0x5b4c
#else
    
    /*!
     * \brief Header macro for object array class. Chars of "[L".
     */
    #define HEADER_KLASS_OBJ_ARRAY   0x4c5b
#endif

/*!
 * \brief Header macro for array class. Chars of "[".
 */
#define HEADER_KLASS_ARRAY           0x5b

/* Function. */

/* Function for utilities. */

/*!
 * \brief Convert COOP(narrowOop) to wide Oop(normally Oop).
 * \param narrowOop [in] Java heap object(compressed format Oop).
 * \return Wide OopDesc object.
 */
inline void *getWideOop(unsigned int narrowOop) {
    
    /*
     * narrow oop decoding is defined in
     * inline oop oopDesc::decode_heap_oop_not_null(narrowOop v)
     * hotspot/src/share/vm/oops/oop.inline.hpp
     */
    
    return (void*)(narrowOffsetBase +
        ((ptrdiff_t)narrowOop << narrowOffsetShift));
}

/*!
 * \brief Convert COOP(narrowKlass) to wide Klass(normally Klass).
 * \param narrowKlass [in] Java Klass object(compressed Klass pointer).
 * \return Wide Klass object.
 */
inline void *getWideKlass(unsigned int narrowKlass) {
    
    /*
     * narrowKlass decoding is defined in
     * inline Klass* Klass::decode_klass_not_null(narrowKlass v)
     * hotspot/src/share/vm/oops/klass.inline.hpp
     */
    
    return (void*)(narrowKlassOffsetBase +
        ((ptrdiff_t)narrowKlass << narrowKlassOffsetShift));
}

/*!
 * \brief Getting oop's class information(It's "Klass", not "KlassOop").
 * \param klassOop [in] Java heap object(Inner "KlassOop" class).
 * \return Class information object(Inner "Klass" class).
 */
void *getKlassFromKlassOop(void *klassOop) {
    if (unlikely(klassOop == NULL || enableCR6964458)) {
        return klassOop;
    }
    return incAddress(klassOop, clsSizeKlassOop);
}

/*!
 * \brief Getting oop's class information(It's "Klass", not "KlassOop").
 * \param oop [in] Java heap object(Inner class format).
 * \return Class information object.
 * \sa oopDesc::klass()<br>
 *     at hotspot/src/share/vm/oops/oop.inline.hpp in JDK.
 */
void *getKlassOopFromOop(void *oop){

  /* Sanity check. */
  if (unlikely(oop == NULL)) {
      return NULL;
  }

  void *tempAddr = NULL;

  /* If JVM use "C"ompressed "OOP". */
  if(isCOOP){
    /* Get oop's klassOop from "_compressed_klass" field. */
    unsigned int* testAddr = (unsigned int*)((ptrdiff_t)oop + ofsCoopKlassAtOop);

    if(likely(testAddr != NULL)){
      /* Decode COOP. */
      tempAddr = getWideKlass(*testAddr);
    }

  }
  else{
    /* Get oop's klassOop from "_klass" field. */
    void **testAddr = (void**)incAddress(oop, ofsKlassAtOop);

    if(likely(testAddr != NULL)){
      tempAddr = (*testAddr);
    }

  }

  return tempAddr;
}

/*!
 * \brief Getting class's name form java inner class.
 * \param klass [in] Java class object(Inner class format).
 * \return String of object class name.<br>
 *         Don't forget deallocate if value isn't null.
 */
char *getClassName(void *klass) {
    
    /* Sanity check. */
    if (unlikely(klass == NULL)) {
        return NULL;
    }
    
    /* Get class symbol information. */
    void **klassSymbol = (void**)incAddress(klass, ofsNameAtKlass);
    if (unlikely(klassSymbol == NULL || (*klassSymbol) == NULL)) {
        return NULL;
    }
    
    /* Get class name pointer. */
    char *name = (char*)incAddress((*klassSymbol), ofsBodyAtSymbol);
    if (unlikely(name == NULL)) {
        return NULL;
    }
    
    bool isInstanceClass = (*name != '[');
    
    /* Get class name size. */
    unsigned short len = *(unsigned short*)
        incAddress((*klassSymbol), ofsLengthAtSymbol);
    
    char *str = NULL;
    /* If class is instance class. */
    if (isInstanceClass) {
        
        /* Add length of "L" and ";". */
        str = (char*)malloc(len + 3);
    } else {
        
        /* Get string memory. */
        str = (char*)malloc(len + 1);
    }
    
    if (likely(str != NULL)) {
        
        /* Get class name. */
        if (isInstanceClass) {
            
            /* Copy class name if class is instance class. */
            /* As like "instanceKlass::signature_name()".  */
            str[0] = 'L';
            //memcpy(&str[1], name, len);
            __builtin_memcpy(&str[1], name, len);
            str[len + 1] = ';';
            str[len + 2] = '\0';
        } else {
            
            /* Copy class name if class is other. */
            //memcpy(str, name, len);
            __builtin_memcpy(str, name, len);
            str[len] = '\0';
        }
    }
    
    return str;
}

/*!
 * \brief Get oop forward address.
 * \param oop [in] Java heap object.
 * \return Wide OopDesc object.
 */
inline void *getForwardAddr(void *oop) {
    
    /* Sanity check. */
    if (unlikely(oop == NULL)) {
        return NULL;
    }
    
    /* Get OopDesc::_mark field. */
    ptrdiff_t markOop = *(ptrdiff_t*)incAddress(oop, ofsMarkAtOop);
    return (void*)(markOop & ~lockMaskInPlaceMarkOop);
}

/*!
 * \brief Is marked object on CMS bitmap.
 * \param oop [in] Java heap object(Inner class format).
 * \return Value is true, if object is marked.
 */
inline bool isMarkedObject(void *oop) {
    size_t idx  = (((ptrdiff_t)oop - (ptrdiff_t)cmsBitMap_startWord)
        >> ((unsigned)LogHeapWordSize + (unsigned)cmsBitMap_shifter));
    size_t mask = (size_t)1 << (idx & BitsPerWordMask);
    return (((size_t*)cmsBitMap_startAddr)[(idx >> LogBitsPerWord)] & mask) != 0;
}

/*!
 * \brief Switching override function enable state.
 * \param list   [in] List of hooking information.
 * \param enable [in] Enable of override function.
 * \return Process result.
 */
bool switchOverrideFunction(THookFunctionInfo *list, bool enable) {
    
    /* Variable for list pointer. */
    THookFunctionInfo *arr = list;
    /* Variable for list item count. */
    int listCnt = 0;
    /* Variable for succeed count. */
    int doneCnt = 0;
    
    /* Search class and function symbol. */
    for (; arr->originalFunc != NULL; listCnt++) {
        
        /* Variable for store vtable. */
        void **vtable = arr->vtable;
        /* Variable for store function pointer. */
        void *targetFunc = NULL;
        void *destFunc = NULL;
        
        /* Setting swap target and swap dest. */
        if (enable) {
            targetFunc = arr->originalFunc;
            destFunc   = arr->overrideFunc;
        } else {
            targetFunc = arr->overrideFunc;
            destFunc   = arr->originalFunc;
        }
        
        if (unlikely(vtable == NULL || targetFunc == NULL || destFunc == NULL)) {
            /* Skip illegal. */
            arr++;
            continue;
        }
        
        const int VTABLE_SKIP_LIMIT = 1000;
        for (int i = 0; i < VTABLE_SKIP_LIMIT && *vtable == NULL; i++) {
            /* Skip null entry. */
            vtable++;
        }
        
        while (*vtable != NULL) {
            /* If target function. */
            if(*vtable == targetFunc){

              if(unlikely(!arr->isVTableWritable)){
                /* Avoid memory protection for vtable
                 *   libstdc++ may remove write permission from vtable
                 *   http://gcc.gnu.org/ml/gcc-patches/2012-11/txt00001.txt
                 */
                ptrdiff_t start_page = (ptrdiff_t)vtable & ~(systemPageSize - 1);
                ptrdiff_t end_page =
                    ((ptrdiff_t)vtable + sizeof(void *)) & ~(systemPageSize - 1);
                size_t len = systemPageSize + (end_page - start_page);
                mprotect((void *)start_page, len, PROT_READ | PROT_WRITE);
                arr->isVTableWritable = true;
              }

              *vtable = destFunc;
              doneCnt++;
              break;
            }
            
            /* Move next vtable entry. */
            vtable++;
        }
        
        /* Move next list item. */
        arr++;
    }
    
    return (listCnt == doneCnt);
}

/*!
 * \brief Get first field object block for "InstanceKlass".
 * \param klassOop [in] Class information object(Inner "Klass" class).
 * \return Oop's field information inner class object("OopMapBlock" class).
 * \sa hotspot/src/share/vm/oops/instanceKlass.hpp
 *     InstanceKlass::start_of_static_fields()
 */
inline void *getBeginBlock(void *klassOop) {
    
    /*
     * Memory map of "klass(InstanceKlass)" class.
     * - Klass object head pointer -
     * - OopDesc                   -
     * - InstanceKlass             -
     * - Java's v-table            -
     * - Java's i-table            -
     * - Static field oops(Notice) -
     * - Non-Static field oops     -
     * Notice - By CR7017732, this area is removed.
     */
    
    void *klass = getKlassFromKlassOop(klassOop);
    if (unlikely(klass == NULL)) {
        return NULL;
    }

    /* Move to v-table head. */
    off_t ofsStartVTable = enableCR6964458
               ? ALIGN_POINTER_OFFSET(clsSizeInstanceKlass / HeapWordSize)
               : ALIGN_POINTER_OFFSET((clsSizeOopDesc / HeapWordSize)
                                       + (clsSizeInstanceKlass / HeapWordSize));

    void *startVTablePtr = (intptr_t*)klassOop + ofsStartVTable;
    
    int vTableLen = *(int*)incAddress(klass, ofsVTableSizeAtInsKlass);
    /* Increment v-table size. */
    void *startITablePtr = (intptr_t*)startVTablePtr
        + ALIGN_POINTER_OFFSET(vTableLen);
    
    int iTableLen = *(int*)incAddress(klass, ofsITableSizeAtInsKlass);
    /* Increment i-table size. */
    void *startStaticFieldPtr = (intptr_t*)startITablePtr
        + ALIGN_POINTER_OFFSET(iTableLen);
    
    if (enableCR7017732) {
        return startStaticFieldPtr;
    }
    
    /* Increment static field size. */
    int staticFieldSize = *(int*)incAddress(klass,
        ofsStaticFieldSizeAtInsKlass);
    return (intptr_t*)startStaticFieldPtr + staticFieldSize;
}

/*!
 * \brief Get number of field object blocks for "InstanceKlass".
 * \param instanceKlass [in] Class information object about "InstanceKlass".
 *                           (Inner "Klass" class)
 * \return Oop's field information inner class object("OopMapBlock" class).
 * \sa hotspot/src/share/vm/oops/instanceKlass.hpp
 *     InstanceKlass::nonstatic_oop_map_count()
 */
inline int getBlockCount(void *instanceKlass) {
    /* Get total field size. */
    int nonstaticFieldSize = 
        *(int*)incAddress(instanceKlass, ofsNonstatiOopMapSizeAtInsKlass);
    /* Get single field size. */
    int sizeInWord = ALIGN_SIZE_UP(sizeof(TOopMapBlock), HeapWordSize)
        >> LogHeapWordSize;
    /* Calculate number of fields. */
    return nonstaticFieldSize / sizeInWord;
}

/*!
 * \brief Get class loader that loaded expected class as KlassOop.
 * \param klassName [in] String of target class name (JNI class format).
 * \return Java heap object which is class loader load expected the class.
 */
TOopType getClassType(const char* klassName) {
    TOopType result = otIllegal;
    
    if (likely(klassName != NULL)) {
        if (*(unsigned short*)klassName == HEADER_KLASS_ARRAY_ARRAY) {
            result = otArrayArray;
        } else if (*(unsigned short*)klassName == HEADER_KLASS_OBJ_ARRAY) {
            result = otObjArarry;
        } else if (*klassName == HEADER_KLASS_ARRAY) {
            result = otArray;
        } else {
            
            /* Expected class name is instance class. */
            result = otInstance;
        }
    }
    return result;
}

/*!
 * \brief Get class loader that loaded expected class as KlassOop.
 * \param klassOop [in] Class information object(Inner "Klass" class).
 * \param type     [in] KlassOop type.
 * \return Java heap object which is class loader load expected the class.
 */
void *getClassLoader(void *klassOop, const TOopType type) {
    void *classLoader = NULL;
    void *klass = getKlassFromKlassOop(klassOop);
    /* Sanity check. */
    if (unlikely(klassOop == NULL || klass == NULL)) {
        return NULL;
    }
    
    switch (type) {
        case otObjArarry:
            classLoader = getClassLoaderForObjArrayKlass(klass);
            break;
        case otInstance:
            classLoader = getClassLoaderForInstanceKlass(klass);
            break;
        case otArray:
        case otArrayArray:
            /*
             * This type oop has no class loader.
             * Because such oop is loaded by system bootstrap class loader.
             * Or the class is loaded at system initialize (e.g. "Universe").
             */
        default:
            ;
    }
    return classLoader;
}

/*!
 * \brief This dummy function for "is_in_permanent".<br>
 * \param thisptr [in] Heap object instance.
 * \param oop     [in] Java object.
 * \return Always value is "false".
 */
bool dummyIsInPermanent(void *thisptr, void *oop) {
    return false;
}

/* Function for callback. */

/*!
 * \brief Follow oop field block.
 * \param event     [in] Callback function.
 * \param fieldOops [in] Pointer of field block head.
 * \param count     [in] Count of field block.
 * \param data      [in] User expected data.
 */
inline void followFieldBlock(THeapObjectCallback event, void **fieldOops,
    const unsigned int count, void* data) {
    
    /* Follow oop at each block. */
    for (unsigned int idx = 0; idx < count; idx++) {
        void *childOop = NULL;
        
        /* Sanity check. */
        if (unlikely(fieldOops == NULL)) {
                continue;
        }
        
        /* Get child oop and move next array item. */
        if (isCOOP) {
            
            /* If this field is not null. */
            if (likely((*(unsigned int*)fieldOops) != 0)) {
                childOop = getWideOop(*(unsigned int*)fieldOops);
            }
            
            fieldOops = (void**)((unsigned int*)fieldOops + 1);
        } else {
            childOop = *fieldOops++;
        }
        
        /* Check oops isn't in permanent generation. */
        if (childOop != NULL && !is_in_permanent(collectedHeap, childOop)) {
            
            /* Invoke callback. */
            event(childOop, data);
        }
    }
}

/*!
 * \brief Generate oop field offset cache.
 * \param klassOop [in]  Target class object(klassOop format).
 * \param oopType  [in]  Type of inner "Klass" type.
 * \param offsets  [out] Field offset array.<br />
 *                       Please don't forget deallocate this value.
 * \param count    [out] Count of field offset array.
 */
void generateIterateFieldOffsets(void *klassOop, TOopType oopType,
    TOopMapBlock **offsets, int *count) {
    
    /* Sanity check. */
    if (unlikely(klassOop == NULL || offsets == NULL || count == NULL)) {
        return;
    }
    
    void *klass = getKlassFromKlassOop(klassOop);
    if (unlikely(klass == NULL)) {
        return;
    }
    
    TOopMapBlock *block = NULL;
    /* Get field blocks. */
    switch (oopType) {
        case otInstance: {
            int blockCount = getBlockCount(klass);
            TOopMapBlock *mapBlock = (TOopMapBlock*)getBeginBlock(klassOop);
            
            /* Allocate block offset records. */
            block = (TOopMapBlock*)malloc(sizeof(TOopMapBlock) * blockCount);
            if (likely(mapBlock != NULL && block != NULL && blockCount > 0)) {
                
                /* Follow each block. */
                for (int i = 0; i < blockCount; i++) {
                    
                    /* Store block information. */
                    block[i].offset = mapBlock->offset;
                    block[i].count  = mapBlock->count;
                    
                    /* Go next block. */
                    mapBlock++;
                }
                
                (*offsets) = block;
                (*count)   = blockCount;
            } else {
                /* If class has no field. */
                if (blockCount == 0) {
                    (*offsets) = NULL;
                    (*count)   = 0;
                }
                
                /* Deallocate memory. */
                free(block);
            }
            break;
        }
        case otObjArarry: {
            
            /* Allocate a block offset record. */
            block = (TOopMapBlock*)malloc(sizeof(TOopMapBlock));
            if (likely(block != NULL)) {
                
                /*
                 * Get array's length field and array field offset.
                 * But such fields isn't define by C++. So be cafeful.
                 * Please see below source file about detail implementation.
                 * hostpost/src/share/vm/oops/arrayOop.hpp
                 */
                block->count  = isCOOP ? (ofsKlassAtOop + clsSizeNarrowOop)
                                       : clsSizeArrayOopDesc;
                block->offset =
                    ALIGN_SIZE_UP(block->count + sizeof(int), HeapWordSize);
                
                (*offsets) = block;
                (*count)   = 1;
            }
            break;
        }
        default:
            /* The oop has no field.  */
            ;
    }
}

/*!
 * \brief Iterate oop's field oops.
 * \param event       [in]     Callback function.
 * \param oop         [in]     Itearate target object(OopDesc format).
 * \param oopType     [in]     Type of oop's class.
 * \param ofsData     [in,out] Cache data for iterate oop fields.<br />
 *                             If value is null, then create and set cache data.
 * \param ofsDataSize [in,out] Cache data count.<br />
 *                             If value is null, then set count of "ofsData".
 * \param data        [in,out] User expected data for callback.
 */
void iterateFieldObject(THeapObjectCallback event, void *oop, TOopType oopType,
    TOopMapBlock **ofsData, int *ofsDataSize, void* data) {
    
    /* Sanity check. */
    if (unlikely(oop  == NULL || event          == NULL
        || ofsData    == NULL || ofsDataSize    == NULL
        || (*ofsData) == NULL || (*ofsDataSize) <= 0)) {
        
        return;
    }
    
    /* If oop has no field. */
    if (unlikely(!hasOopField(oopType))) {
        
        return;
    }
    
    /* Use expected data by function calling arguments. */
    TOopMapBlock *offsets = (*ofsData);
    int offsetCount = (*ofsDataSize);
    
    if (oopType == otInstance) {
        
        /* Iterate each oop field block as "Instance klass". */
        for (TOopMapBlock *endOfs = offsets + offsetCount;
            offsets < endOfs; offsets++) {
            
            followFieldBlock(event,
                (void**)incAddress(oop, offsets->offset),
                offsets->count, data);
        }
    } else {
        
        /* Iterate each oop field block as "ObjArray klass". */
        followFieldBlock(event,
            (void**)incAddress(oop, offsets->offset),
            *(int*)incAddress(oop, offsets->count), data);
    }
}

/*!
 * \brief Callback function for parallel GC and user's GC.<br>
 *        E.g. System.gc() in java code, JVMTI and etc..
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
extern "C" void callbackForParallel(void *oop) {
    
    /* Invoke callback by GC. */
    gcCallbackFunc(oop, NULL);
    isInvokedParallelGC = true;
}

/*!
 * \brief Callback function for parallel Old GC.
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
extern "C" void callbackForParOld(void *oop) {
    
    /* Invoke callback by GC. */
    gcCallbackFunc(oop, NULL);
    isInvokedParallelGC = true;
}

/*!
 * \brief Callback function for OopClosure::do_oop(oop *).<br>
 *        This function is targeted for G1ParScanAndMarkExtRootClosure.
 *        (initial-mark for G1)
 * \param oop [in] Java heap object(OopDesc format).
 */
extern "C" void callbackForDoOop(void **oop){

  if((oop == NULL) || (*oop == NULL) || is_in_permanent(collectedHeap, *oop)){
    return;
  }

  if(checkObjectMap->checkAndMark(*oop)){
    /* Object is already collected by G1GC collector. */
    return;
  }

  /* Invoke snapshot callback. */
  gcCallbackFunc(*oop, NULL);
}

/*!
 * \brief Callback function for OopClosure::do_oop(narrowOop *).<br>
 *        This function is targeted for G1ParScanAndMarkExtRootClosure.
 *        (initial-mark for G1)
 * \param oop [in] Java heap object(OopDesc format).
 */
extern "C" void callbackForDoNarrowOop(unsigned int *narrowOop){
  void *oop = getWideOop(*narrowOop);
  callbackForDoOop(&oop);
}

/*!
 * \brief Callback function for CMS GC and G1 GC.<br>
 *        This function is targeted for Young Gen only.
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 * \sa CMSParRemarkTask::do_young_space_rescan()<br>
 *     ContiguousSpace::par_oop_iterate()
 */
extern "C" void callbackForIterate(void *oop) {

  if(useCMS){

    /* If object is in CMS gen.  */
    if((ptrdiff_t)oop >= (ptrdiff_t)cmsBitMap_startWord){
      /* Skip. because collect object in CMS gen by callbackForSweep. */
      return;
    }

    /* Invoke callback by CMS GC. */
    cmsCallbackFunc(oop, NULL);
  }
  else if(useG1){

    if(checkObjectMap->checkAndMark(oop)){
      /* Object is already collected by G1GC collector. */
      return;
    }

    /* Invoke callback by GC. */
    gcCallbackFunc(oop, NULL);
    isInvokedParallelGC = true;
  }

}

/*!
 * \brief Callback function for CMS sweep.<br>
 *        This function is targeted for CMS Gen only.
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
extern "C" void callbackForSweep(void *oop) {
    
    /* If object isn't GC target. */
    if (likely(isMarkedObject(oop))) {
        
        /* Invoke callback by CMS GC. */
        cmsCallbackFunc(oop, NULL);
    }
}

/*!
 * \brief Callback function for klassOop.
 * \param oldOop [in] Old java class object.
 * \param newOop [in] New java class object.
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
inline void callbackForAdjustKlass(void *oldOop, void *newOop) {
    if (likely(adjustCallbackFunc != NULL)) {
        adjustCallbackFunc(oldOop, newOop);
    }
}

/*!
 * \brief Callback function for oop_adjust_pointers.
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
extern "C" void callbackForAdjustPtr(void *oop) {
    
    /* Get new class oop. */
    void *newOop = getForwardAddr(oop);
    if (newOop != NULL) {
        
        /* Invoke callback. */
        callbackForAdjustKlass(oop, newOop);
    }
}

/*!
 * \brief Callback function for do_addr.
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
extern "C" void callbackForDoAddr(void *oop) {
    
    /* Get store memory. */
    void **oldOop = (void**)pthread_getspecific(oldKlassOopKey);
    if (unlikely(oldOop == NULL)) {
        
        /* Allocate and set store memory. */
        oldOop = (void**)malloc(sizeof(void*));
        pthread_setspecific(oldKlassOopKey, oldOop);
    }
    
    /* Store old klassOop. */
    if (likely(oldOop != NULL)) {
        (*oldOop) = oop;
    }
}

/*!
 * \brief Callback function for oop_update_pointers.
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
extern "C" void callbackForUpdatePtr(void *oop) {
    
    /* Get old class oop. */
    void **oldOop = (void**)pthread_getspecific(oldKlassOopKey);
    
    if (likely(oldOop != NULL && (*oldOop) != NULL)) {
        
        /* Invoke callback. */
        callbackForAdjustKlass((*oldOop), oop);
        
        /* Cleanup old data. */
        (*oldOop) = NULL;
    }
}

/*!
 * \brief Callback function for snapshot with data dump or interval.
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
extern "C" void callbackForJvmtiIterate(void *oop) {
    
    /* Invoke callback by JVMTI. */
    jvmtiIteCallbackFunc(oop, NULL);
}

/*!
 * \brief Callback function for before G1 GC cleanup.
 */
extern "C" void callbackForG1Cleanup(void) {
    
    if (likely(g1FinishCallbackFunc != NULL)) {
        
        /* Invoke callback. */
        g1FinishCallbackFunc();
    }
    
    /* Clear bitmap. */
    checkObjectMap->clear();
}

/*!
 * \brief Callback function for before System.gc() on using G1GC.
 * \param isFull [in] Is this event FullGC?
 */
extern "C" void callbackForG1Full(bool isFull){

  /* This function must be processed when FullGC occurs.
   * e.g. System.gc(), evacuation failure, etc...
   */
  if(!isFull){
    return;
  }

  /*
   * Disable G1 callback function:
   *  OopClosure for typeArrayKlass is called by G1 FullCollection.
   */
  switchOverrideFunction(g1_hook, false);

  /* Discard existed snapshot data */
  snapshotByGC->clear(false);
  checkObjectMap->clear();
}

/*!
 * \brief Callback function for after System.gc() on using G1GC.
 * \param isFull [in] Is this event FullGC?
 */
extern "C" void callbackForG1FullReturn(bool isFull){

  /* This function must be processed when FullGC occurs.
   * e.g. System.gc(), evacuation failure, etc...
   */
  if(!isFull){
    return;
  }

  /* Restore G1 callback. */
  switchOverrideFunction(g1_hook, true);

  if(likely(g1FinishCallbackFunc != NULL)){
    /* Invoke callback. */
    g1FinishCallbackFunc();
  }

  /* Clear bitmap. */
  checkObjectMap->clear();
}

/*!
 * \brief Callback function for starting inner GC.
 */
extern "C" void callbackForInnerGCStart(void) {
  /* If call GC function more one. */
  if (unlikely(isInvokeGCManyTimes)) {
        
      /* Invoke GC interrupt callback. */
      if (likely(gcInterruptCallbackFunc != NULL)) {
          gcInterruptCallbackFunc();
      }
  }
  else{
    /* Update state. */
    isInvokeGCManyTimes = true;
  }

  /* Get current GCCause. */
  jvmInfo->loadGCCause();
}

/*!
 * \brief Callback function for WatcherThread.
 */
extern "C" void callbackForWatcherThreadRun(void){
  jvmInfo->detectDelayInfoAddress();
 }


/* Function for pthread. */

/*!
 * \brief Callback for pthread key destructor.
 * \param data [in] Data related to pthread key.
 */
void pThreadKeyDestructor(void *data) {
    if (likely(data != NULL)) {
        
        /* Cleanup allocated memory on "callbackForDoAddr". */
        free(data);
    }
}

/* Function for init/final. */

/*!
 * \brief Search common JVM information structures at "OnVMInit".
 * \return Process result.
 */
bool searchCommonInformation(void) {
    int *narrowOffsetShiftBuf = NULL;
    int *narrowKlassOffsetShiftBuf = NULL;

    /* List of common field offset. */
    TOffsetNameMap ofsMap[] = {
        {"Universe", "_collectedHeap",
            NULL,               &collectedHeap},
        {"Universe", "_narrow_oop._base",
            NULL,               (void **)&narrowOffsetBase},
        {"Universe", "_narrow_oop._shift",
            NULL,               (void **)&narrowOffsetShiftBuf},
        {"Universe", "_narrow_klass._base",
            NULL,               (void **)&narrowKlassOffsetBase},
        {"Universe", "_narrow_klass._shift",
            NULL,               (void **)&narrowKlassOffsetShiftBuf},
        {"oopDesc",  "_metadata._klass",
            &ofsKlassAtOop,     NULL},
        {"oopDesc",  "_metadata._compressed_klass",
            &ofsCoopKlassAtOop, NULL},
        {"oopDesc",  "_mark",
            &ofsMarkAtOop,      NULL},
        {"Klass",    "_name",
            &ofsNameAtKlass,    NULL},
        
        /*
         * For CR6990754.
         * Use native memory and reference counting to implement SymbolTable.
         */
        {"symbolOopDesc", "_length", &ofsLengthAtSymbol, NULL},
        {"symbolOopDesc", "_body",   &ofsBodyAtSymbol,   NULL},
        {"Symbol",        "_length", &ofsLengthAtSymbol, NULL},
        {"Symbol",        "_body",   &ofsBodyAtSymbol,   NULL},
        
        {"instanceKlass", "_vtable_len",
            &ofsVTableSizeAtInsKlass,         NULL},
        {"instanceKlass", "_itable_len",
            &ofsITableSizeAtInsKlass,         NULL},
        {"instanceKlass", "_static_field_size",
            &ofsStaticFieldSizeAtInsKlass,    NULL},
        {"instanceKlass", "_nonstatic_oop_map_size",
            &ofsNonstatiOopMapSizeAtInsKlass, NULL},

        /* For CR6964458 */
        {"InstanceKlass", "_vtable_len",
            &ofsVTableSizeAtInsKlass,         NULL},
        {"InstanceKlass", "_itable_len",
            &ofsITableSizeAtInsKlass,         NULL},
        {"InstanceKlass", "_static_field_size",
            &ofsStaticFieldSizeAtInsKlass,    NULL},
        {"InstanceKlass", "_nonstatic_oop_map_size",
            &ofsNonstatiOopMapSizeAtInsKlass, NULL},
        
        /* End flag. */
        {NULL, NULL, NULL, NULL}
    };
    
    vmScanner->GetDataFromVMStructs(ofsMap);
    
    /* If failure getting common field  offset information. */
    if (unlikely(collectedHeap     == NULL || narrowOffsetBase        ==  0
        || narrowOffsetShiftBuf    == NULL || ofsKlassAtOop           == -1
        || ofsCoopKlassAtOop       == -1   || ofsNameAtKlass          == -1
        || ofsLengthAtSymbol       == -1   || ofsBodyAtSymbol         == -1
        || ofsVTableSizeAtInsKlass == -1   || ofsITableSizeAtInsKlass == -1
        || (!enableCR7017732 && (ofsStaticFieldSizeAtInsKlass == -1))
        || ofsNonstatiOopMapSizeAtInsKlass == -1)) {
        
        PRINT_WARN_MSG("Failure getting information form JVM."
            " info:Common from:VMStructs");
        return false;
    }

    narrowOffsetShift = *narrowOffsetShiftBuf;

    if(!enableCR8003424){
      narrowKlassOffsetBase = narrowOffsetBase;
      narrowKlassOffsetShift = narrowOffsetShift;
    }
    else{
      narrowKlassOffsetShift = *narrowKlassOffsetShiftBuf;
    }

    /* List of common class size. */
    TTypeSizeMap typeMap[] = {
        /*
         * After CR6964458.
         * Not exists class "klassOopDesc".
         */
        {"klassOopDesc",  &clsSizeKlassOop},
        {"oopDesc",       &clsSizeOopDesc},
        {"instanceKlass", &clsSizeInstanceKlass},
        {"InstanceKlass", &clsSizeInstanceKlass},
        {"arrayOopDesc",  &clsSizeArrayOopDesc},
        {"narrowOop",     &clsSizeNarrowOop},
        /* End flag. */
        {NULL, NULL}
    };
    
    vmScanner->GetDataFromVMTypes(typeMap);
    
    /* If failure getting common class size information. */
    if (unlikely((!enableCR6964458 && clsSizeKlassOop == 0)
        || clsSizeOopDesc == 0 || clsSizeInstanceKlass == 0
        || clsSizeArrayOopDesc == 0 || clsSizeNarrowOop == 0)) {
        
        PRINT_WARN_MSG("Failure getting information form JVM."
            " info:Common from:VMTypes");
        return false;
    }
    
    /* List of common long constant. */
    TLongConstMap longMap[] = {
        {"markOopDesc::lock_mask_in_place", &lockMaskInPlaceMarkOop},
        /* End flag. */
        {NULL, NULL}
    };
    
    vmScanner->GetDataFromVMLongConstants(longMap);
    
    /* If failure getting common class size information. */
    if (unlikely(lockMaskInPlaceMarkOop == 0)) {
        
        PRINT_WARN_MSG("Failure getting information form JVM."
            " info:Common from:VMLongConstants");
        return false;
    }
    
    /* List of integer constant data target. */
    TIntConstMap intMap[] = {
        {"HeapWordSize",    &HeapWordSize},
        {"LogHeapWordSize", &LogHeapWordSize},
        /* End flag. */
        {NULL, NULL}
    };
    
    vmScanner->GetDataFromVMIntConstants(intMap);
    
    return true;
}

/*!
 * \brief Search common flag.
 * \return Process result.
 */
bool searchCommonFlags(void) {
    
    /* Search flag symbols. */
    struct {
        const char *symbolStr;
        bool *flagPtr;
    } flagList[] = {
#ifdef __LP64__
        {"UseCompressedOops",  &isCOOP},
#endif
        {"UseParallelGC",      &useParallel},
        {"UseParallelOldGC",   &useParOld},
        {"UseConcMarkSweepGC", &useCMS},
        {"UseG1GC",            &useG1},
        /* End flag. */
        {NULL, NULL}
    };
    
    for (int i = 0; flagList[i].flagPtr != NULL; i++) {
        bool *tempPtr = NULL;
        
        /* Search symbol. */
        tempPtr = (bool*)symFinder->findSymbol(flagList[i].symbolStr);
        
        /* If symbol not found. */
        if (unlikely(tempPtr == NULL)) {
            PRINT_WARN_MSG_HEADER << "Java symbol not found."
                << " symbol:\"" << flagList[i].symbolStr << "\"" << NEWLINE;
            return false;
        }
        
        *(flagList[i].flagPtr) = *tempPtr;
    }

#ifdef __LP64__
  if(enableCR6964458){
    bool *tempPtr = NULL;
    const char *target_sym = enableCR8015107
                                  ? "UseCompressedClassPointers"
                                  : "UseCompressedKlassPointers";

    /* Search symbol. */
    tempPtr = (bool*)symFinder->findSymbol(target_sym);

    /* If symbol not found. */
    if (unlikely(tempPtr == NULL)) {
      PRINT_WARN_MSG_HEADER << target_sym << " not found." << NEWLINE;
    }
    else{
      isCOOP = *tempPtr;
    }

  }
#endif

  if(isCOOP){
    PRINT_DEBUG_MSG("Compressed Class = true");
  }
  else{
    PRINT_DEBUG_MSG("Compressed Class = false");
  }

    if(useG1){
      /* Add vtable offset */
#ifdef __LP64__
      VTableForTypeArrayOopClosure[0] =
          incAddress(symFinder->findSymbol("_ZTV14G1CMOopClosure"), 16);
      VTableForTypeArrayOopClosure[1] =
          incAddress(symFinder->findSymbol("_ZTV23G1RootRegionScanClosure"), 16);
#else
      VTableForTypeArrayOopClosure[0] =
          incAddress(symFinder->findSymbol("_ZTV14G1CMOopClosure"), 8);
      VTableForTypeArrayOopClosure[1] =
          incAddress(symFinder->findSymbol("_ZTV23G1RootRegionScanClosure"), 8);
#endif
    }
    
    /* Search symbol for integer information. */
    struct {
        const char *symbol;
        const char *subSymbol;
        int *pointer;
    } intSymList[] = {
        {"HeapWordsPerLong", "_ZL16HeapWordsPerLong", &HeapWordsPerLong},
        {"LogBitsPerWord",   "_ZL14LogBitsPerWord",   &LogBitsPerWord},
        {"BitsPerWord",      "_ZL11BitsPerWord",      &BitsPerWord},
        /* End flag. */
        {NULL, NULL, NULL}
    };
    
    for (int i = 0; intSymList[i].pointer != NULL; i++) {
        int *intPos = NULL;
        intPos = (int*)symFinder->findSymbol(intSymList[i].symbol);
        
        /* If integer symbol not found, search sub-symbol. */
        if (unlikely(intPos == NULL)) {
            intPos = (int*)symFinder->findSymbol(intSymList[i].subSymbol);
        }
        
        /* If integer symbol and sub-symbol not found. */
        if (unlikely(intPos == NULL)) {
            PRINT_DEBUG_MSG_HEADER
                << "Java symbol not found, using default value instead."
                << " symbol:\"" << intSymList[i].symbol << "\""
                << NEWLINE;
        } else {
            (*intSymList[i].pointer) = (*intPos);
        }
    }
    return true;
}

/*!
 * \brief Search common function.
 * \return Process result.
 */
bool searchCommonFunction(void) {
    
    /* Search "is_in_permanent" function symbol. */
    if (enableCR6964458) {
        
        /* Perm gen isn't exists. */
        is_in_permanent = (THeap_IsInPermanent)&dummyIsInPermanent;
    } else if (useParallel || useParOld){
        
        is_in_permanent = (THeap_IsInPermanent)symFinder->findSymbol(
            IS_IN_PERM_ON_PARALLEL_GC_SYMBOL);
    } else {
        
        is_in_permanent = (THeap_IsInPermanent)symFinder->findSymbol(
            IS_IN_PERM_ON_OTHER_GC_SYMBOL);
    }
    /* If not found "is_in_permanent" function symbol. */
    if (unlikely(is_in_permanent == NULL)) {
        PRINT_WARN_MSG("Java symbol not found. symbol:\"is_in_permanent\"");
        return false;
    }
    
    /* Search "GetObjectSize" function symbol. */
    getObjectSize = (TJvmtiEnv_GetObjectSize)symFinder->findSymbol(
        SYMBOL_GETOBJCTSIZE);
    /* If not found "GetObjectSize" function symbol. */
    if (unlikely(getObjectSize == NULL)) {
        PRINT_WARN_MSG("Java symbol not found. symbol:\"GetObjectSize\"");
        return false;
    }
    
    /* Search "as_klassOop" function symbol. */
    asKlassOop = (TJavaLangClass_AsKlassOop)symFinder->findSymbol(
        (enableCR6964458) ? AS_KLASS_SYMBOL : AS_KLASSOOP_SYMBOL);
    /* If not found "as_klassOop" function symbol. */
    if (unlikely(asKlassOop == NULL)) {
        PRINT_WARN_MSG("Java symbol not found. symbol:\"as_klassOop\"");
        return false;
    }
    
    /* Search symbol of variable stored safepoint state. */
    safePointState = (int*)symFinder->findSymbol(SAFEPOINT_STATE_SYMBOL);
    /* If not found "_state" variable symbol. */
    if (unlikely(safePointState == NULL)) {
        PRINT_WARN_MSG("Java symbol not found. symbol:\"safepoint_state\"");
        return false;
    }
    
    /* Search symbol of function getting classloader. */
    if(enableCR8004883){
      getClassLoaderForInstanceKlass = (TGetClassLoader)symFinder->findSymbol(
                                    CR8004883_GET_CLSLOADER_FOR_INSTANCE_SYMBOL);
      getClassLoaderForObjArrayKlass = (TGetClassLoader)symFinder->findSymbol(
                                      CR8004883_GET_CLSLOADER_FOR_OBJARY_SYMBOL);
    }
    else{
      getClassLoaderForInstanceKlass = (TGetClassLoader)symFinder->findSymbol(
                                              GET_CLSLOADER_FOR_INSTANCE_SYMBOL);
      getClassLoaderForObjArrayKlass = (TGetClassLoader)symFinder->findSymbol(
                                                GET_CLSLOADER_FOR_OBJARY_SYMBOL);
    }

    /* If not found getting classloader function symbol. */
    if (unlikely(getClassLoaderForInstanceKlass == NULL
        || getClassLoaderForObjArrayKlass == NULL)) {
        
        PRINT_WARN_MSG("Java symbol not found. symbol:\"get_classloader\"");
        return false;
    }
    
    return true;
}

/*!
 * \brief Setup override funtion.
 * \param list [in] List of hooking information.
 * \return Process result.
 */
bool setupOverrideFunction(THookFunctionInfo *list) {
    /* Variable for list pointer. */
    THookFunctionInfo *arr = list;
    
    /* Search class and function symbol. */
    for (int i = 0; arr->vtableSymbol != NULL; i++) {
        
        /* Search class(vtable) symbol. */
        arr->vtable = (void**)symFinder->findSymbol(arr->vtableSymbol);
        if (unlikely(arr->vtable == NULL)) {
            PRINT_WARN_MSG_HEADER << "Java symbol not found."
                << " symbol:\"" << arr->vtableSymbol << "\"" << NEWLINE;
            return false;
        }
        
        /* Search function symbol. */
        arr->originalFunc = symFinder->findSymbol(arr->funcSymbol);
        if (unlikely(arr->originalFunc == NULL)) {
            PRINT_WARN_MSG_HEADER << "Java symbol not found."
                << " symbol:\"" << arr->funcSymbol << "\"" << NEWLINE;
            return false;
        }
        
        /* Move next list item. */
        arr++;
    }
    
    return true;
}

/*!
 * \brief Setup GC hooking for parallel.
 * \return Process result.
 */
bool setupForParallel(void) {
    SELECT_HOOK_FUNCS(par);
    
    /* If failure getting function information. */
    if (unlikely(!setupOverrideFunction(par_hook))) {
        
        PRINT_WARN_MSG("Failure function overriding. func:parallel");
        return false;
    }
    
    return true;
}

/*!
 * \brief Setup GC hooking for parallel old GC.
 * \return Process result.
 */
bool setupForParallelOld(void) {
    SELECT_HOOK_FUNCS(parOld);
    
    /* If failure getting function information. */
    if (unlikely(!setupOverrideFunction(parOld_hook))) {
        
        PRINT_WARN_MSG("Failure function overriding. func:par_old");
        return false;
    }
    
    return true;
}

/*!
 * \brief Setup GC hooking for CMSGC.
 * \return Process result.
 */
bool setupForCMS(void) {
    SELECT_HOOK_FUNCS(cms_new);
    
    void *cmsCollector            = NULL;
    off_t offsetLowAtVirtualSpace = -1;
    off_t offsetCmsStartWord      = -1;
    off_t offsetCmsShifter        = -1;
    off_t offsetCmsMapAtCollector = -1;
    off_t offsetCmsVirtualSpace   = -1;
    TOffsetNameMap ofsMap[] = {
        {"CMSBitMap",                 "_virtual_space",
            &offsetCmsVirtualSpace,   NULL},
        {"CMSBitMap",                 "_bmStartWord",
            &offsetCmsStartWord,      NULL},
        {"CMSBitMap",                 "_shifter",
            &offsetCmsShifter,        NULL},
        {"CMSCollector",              "_markBitMap",
            &offsetCmsMapAtCollector, NULL},
        {"ConcurrentMarkSweepThread", "_collector",
            NULL,                     &cmsCollector},
        {"VirtualSpace",              "_low",
            &offsetLowAtVirtualSpace, NULL},
        /* End flag. */
        {NULL, NULL, NULL, NULL}
    };
    
    vmScanner->GetDataFromVMStructs(ofsMap);
    
    /* If not exists "CMSBitMap::_bmStartWord" entry in vmstruct. */
    if (enableCR6964458) {
        off_t bmWordSizeOfs = -1;
        TOffsetNameMap bmWordSizeMap[] = {
            {"CMSBitMap", "_bmWordSize", &bmWordSizeOfs, NULL},
            {NULL, NULL, NULL, NULL}
        };
        
        vmScanner->GetDataFromVMStructs(bmWordSizeMap);
        if (likely(bmWordSizeOfs != -1)) {
            
            /*
             * CMSBitMap::_bmStartWord is appeared before _bmWordSize.
             * See CMSBitMap definition in
             * hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/
             * concurrentMarkSweepGeneration.hpp
             */
            offsetCmsStartWord = bmWordSizeOfs - sizeof(void *);
        }
    }
    
    /* If failure getting offset. */
    if (unlikely(offsetCmsVirtualSpace == -1 || offsetCmsStartWord == -1
        || offsetCmsShifter ==   -1 || offsetCmsMapAtCollector == -1
        || cmsCollector     == NULL || offsetLowAtVirtualSpace == -1
        || *(void**)cmsCollector    == NULL)) {
        
        PRINT_WARN_MSG("Failure getting information form JVM."
            " info:CMS from:vmStructs");
        return false;
    }
    
    /* Calculate about CMS bitmap information. */
    cmsCollector = *(void**)cmsCollector;
    ptrdiff_t cmsBitmapPtr = (ptrdiff_t)cmsCollector + offsetCmsMapAtCollector;
    cmsBitMap_startWord = *(void**)(cmsBitmapPtr + offsetCmsStartWord);
    cmsBitMap_shifter   = *(int*)(cmsBitmapPtr + offsetCmsShifter);
    
    ptrdiff_t virtSpace = cmsBitmapPtr + offsetCmsVirtualSpace;
    cmsBitMap_startAddr = *(size_t**)(virtSpace + offsetLowAtVirtualSpace);
    
    /* If failure getting CMS bitmap information. */
    if(unlikely((cmsBitMap_startWord == NULL) || (cmsBitMap_startAddr == NULL))){
      PRINT_WARN_MSG("Failure getting information form JVM."
                     " info:CMS from:calculate");
      return false;
    }
    
    /* Search symbol for CMS state. */
    CMS_collectorState = (int*)symFinder->findSymbol(
        "_ZN12CMSCollector15_collectorStateE");
    /* If not found "CMS_collectorState" function symbol. */
    if (unlikely(CMS_collectorState == NULL)) {
        PRINT_WARN_MSG("Java symbol not found. symbol:\"CollectorState\"");
        return false;
    }
    
    /* If failure getting function information. */
    if (unlikely(!setupOverrideFunction(cms_new_hook))) {
        
        PRINT_WARN_MSG("Can't override function. func:CMS_new");
        return false;
    }
    
    /* If failure getting function information. */
    if (unlikely(!setupOverrideFunction(cms_sweep_hook))) {
        
        PRINT_WARN_MSG("Can't override function. func:CMS_sweep");
        return false;
    }
    BitsPerWordMask = BitsPerWord - 1;
    return true;
}

/*!
 * \brief Setup GC hooking for G1GC
 * \return Process result.
 */
bool setupForG1GC(size_t maxMemSize) {
    SELECT_HOOK_FUNCS(g1);
    
    off_t offsetG1Committed    = -1;
    off_t offsetMemRegionStart = -1;
    TOffsetNameMap ofsMap[] = {
        {"G1CollectedHeap",        "_g1_committed",
            &offsetG1Committed,    NULL},
        {"MemRegion",              "_start",
            &offsetMemRegionStart, NULL},
        /* End flag. */
        {NULL, NULL, NULL, NULL}
    };
    
    vmScanner->GetDataFromVMStructs(ofsMap);
    
    /* If failure getting offset. */
    if (unlikely(offsetG1Committed == -1 || offsetMemRegionStart == -1
        || collectedHeap == NULL)) {
        
        PRINT_WARN_MSG("Failure getting information form JVM."
            " info:G1 from:vmStructs");
        return false;
    }
    
    /* Calculate about G1GC memory information. */
    void *g1Committed = *(void**)incAddress(collectedHeap, offsetG1Committed);
    void *g1StartAddr = incAddress(g1Committed, offsetMemRegionStart);
    if (unlikely(g1Committed == NULL || g1StartAddr == NULL)) {
        
        PRINT_WARN_MSG("Failure getting information form JVM."
            " info:G1 from:calculate");
        return false;
    }
    
    try {
        /* Sanity check. */
        if (unlikely(maxMemSize <= 0)) {
            throw 1;
        }
        
        /* Create bitmap to check object collected flag. */
        checkObjectMap = new TBitMapMarker(g1StartAddr, maxMemSize);
        
    } catch(...) {
        PRINT_WARN_MSG("Failure allocate object marker bitmap.");
        return false;
    }
    
    /* If failure getting function information. */
    if (unlikely(!setupOverrideFunction(g1_hook)
        || !setupOverrideFunction(g1Event_hook))) {
        
        PRINT_WARN_MSG("Failure function overriding. func:g1");
        return false;
    }
    
    return true;
}

/*!
 * \brief Setting GC hooking enable.
 * \param enable [in] Is GC hook enable.
 * \return Process result.
 */
bool setGCHookState(bool enable) {
    
    /* Sanity check. */
    if (unlikely(isEnableGCHooking == enable)) {
        
        /* Already set state. */
        return true;
    }
    /* Change state. */
    isEnableGCHooking = enable;
    
    /* Setting hooking target. */
    THookFunctionInfo *list = NULL;
    if(useParOld){
      list = parOld_hook;
    }
    else if(useCMS){
      /* Switch CMS hooking at new generation. */
      switchOverrideFunction(cms_new_hook, enable);
      list = cms_sweep_hook;
    }
    else if(useG1){
      /* If users select G1, we prepare TSnapShotContainer NOW! */
      snapshotByGC = TSnapShotContainer::getInstance();

      /* Switch G1GC event hooking. */
      switchOverrideFunction(g1Event_hook, enable);

      list = g1_hook;
      checkObjectMap->clear();
    }
    
    /* Switch common hooking. */
    if (unlikely(!switchOverrideFunction(par_hook, enable))) {
        
        PRINT_WARN_MSG("Failure switch function overriding. func:par");
        return false;
    }
    
    /* Switch adjust pointer hooking. */
    if(!enableCR6964458){
      if(unlikely(!switchOverrideFunction(adj_hook, enable))){
        
        PRINT_WARN_MSG("Failure switch function overriding. func:adj-ptr");
        return false;
      }
    }
    
    if (list != NULL) {
        
        /* Switch hooking for each GC type. */
        if (unlikely(!switchOverrideFunction(list, enable))) {
            
            PRINT_WARN_MSG("Failure switch function overriding. func:usingGC");
            return false;
        }
    }
    
    return true;
}

/*!
 * \brief Setting JVMTI hooking enable.
 * \param enable [in] Is JVMTI hook enable.
 * \return Process result.
 */
bool setJvmtiHookState(bool enable) {
    
    /* Sanity check. */
    if (unlikely(isEnableJvmtiHooking == enable)) {
        
        /* Already set state. */
        return true;
    }
    /* Change state. */
    isEnableJvmtiHooking = enable;
    
    /* Switch JVMTI hooking. */
    if (unlikely(!switchOverrideFunction(jvmti_hook, enable))) {
        
        PRINT_WARN_MSG("Failure switch function overriding. func:JVMTI");
        return false;
    }
    
    return true;
}

/*!
 * \brief Initialization of this util.
 * \param jvmti [in] JVMTI environment object.
 * \return Process result.
 */
bool oopUtilInitialize(jvmtiEnv *jvmti) {
    
    /* Search symbol in libjvm. */
    char *libPath = NULL;
    jvmti->GetSystemProperty("sun.boot.library.path", &libPath);
    try {
        /* Create symbol finder instance. */
        symFinder = new TSymbolFinder();
        if (unlikely(!symFinder->loadLibrary(libPath, "libjvm.so"))) {
            throw 1;
        }
        
        /* Cretae VMStruct scanner instance. */
        vmScanner = new TVMStructScanner(symFinder);
    } catch(...) {
        PRINT_CRIT_MSG("Failure getting symbol information.");
        jvmti->Deallocate((unsigned char *)libPath);
        delete symFinder;
        symFinder = NULL;
        return false;
    }
    jvmti->Deallocate((unsigned char *)libPath);
    
    bool result = true;
    try {
        /* Setup HotSpot version. */
        char *versionStr = NULL;
        if (unlikely(isError(jvmti,
            jvmti->GetSystemProperty("java.vm.version", &versionStr)))) {
            
            PRINT_CRIT_MSG("Failure getting JVM version.");
            throw 1;
        } else {
            unsigned char major  = 0;
            unsigned char minor  = 0;
            unsigned char build = 0;
            int result = 0;
            
            /* Parse version string. */
            result = sscanf(versionStr, "%hhu.%hhu-b%hhu",
                                                 &major, &minor, &build);
            /*
             *  We expect to get 3 values (major, minor, build) from sscanf()
             *  at first.
             */
            if(result == 3){
              hotSpotVersion = major << 24 | minor << 16 | build;
            }
            else{
              /* After JDK-8030011: Update Hotspot version string output */
              unsigned short micro = 0;
              result =  sscanf(versionStr, "%hhu.%hhu.%hhu",
                                               &major, &minor, &micro);
              char *build_str = strrchr(versionStr, 'b');
              if(likely(build_str != NULL)){
                result += sscanf(build_str, "b%hhu", &build);
              }

              /*
               * We expect to get 4 values (major, minor, micro, build)
               * from sscanf().
               * This versioning equals to JDK version.
               */
              if (unlikely(result != 4)) {
                PRINT_CRIT_MSG_HEADER << "Unsupported JVM version: "
                                      << versionStr
                                      << " (" << result << ")"
                                      << NEWLINE;
                              
                jvmti->Deallocate((unsigned char *)versionStr);
                throw 1;
              }

              /*
               * Latest HS version is "25".
               * So I add 25 to major.
               */
              major += 25;

              hotSpotVersion = major << 24 | minor << 16 | micro << 8 | build;
            }

            jvmti->Deallocate((unsigned char *)versionStr);
        }
        
        /*
         * See CR7017732:
         * Move static fields into Class to prepare for perm gen removal.
         */
        const unsigned int afterCR7017732 = 21 << 24 | 6;
        enableCR7017732 = (hotSpotVersion >= afterCR7017732);
        
        /*
         * See CR6964458:
         * Reimplement class meta-data storage to use native memory.
         */
        const unsigned int afterCR6964458 = 25 << 24 | 1;
        enableCR6964458 = (hotSpotVersion >= afterCR6964458);
        
        /*
         * See CR8000213:
         * NPG: Should have renamed arrayKlass and typeArrayKlass.
         */
        const unsigned int afterCR8000213 = 25 << 24 | 4;
        enableCR8000213 = (hotSpotVersion >= afterCR8000213);

        /*
         * See JDK-8027746:
         * Remove do_gen_barrier template parameter in G1ParCopyClosure
         */
        const unsigned int afterCR8027746 = 25 << 24 | 20 << 16 | 2;
        enableCR8027746 = (hotSpotVersion >= afterCR8027746);

        /*
         * See CR8004883:
         * 8004883: NPG: clean up anonymous class fix
         */
        const unsigned int afterCR8004883 = 25 << 24 | 14;
        enableCR8004883 = (hotSpotVersion >= afterCR8004883);

        /*
         * See CR8003424:
         * 8003424: Enable Class Data Sharing for CompressedOops
         */
        const unsigned int afterCR8003424 = 25 << 24 | 46;
        enableCR8003424 = (hotSpotVersion >= afterCR8003424);

        /*
         * See CR8015107:
         * 8015107: NPG: Use consistent naming for metaspace concepts
         */
        const unsigned int afterCR8015107 = 25 << 24 | 51;
        enableCR8015107 = (hotSpotVersion >= afterCR8015107);

        /*
         * See JDK-8049421:
         * G1 Class Unloading after completing a concurrent mark cycle
         */
        const unsigned int afterCR8049421 = 25 << 24 | 40 << 16 | 5;
        enableCR8049421 = (hotSpotVersion >= afterCR8049421);

        /* Search flag symbol in libjvm. */
        if (unlikely(!searchCommonFlags())) {
            PRINT_CRIT_MSG("Failure getting java symbol information.");
            throw 1;
        }

        if(useG1){
            /*
             * See 7046558: G1: concurrent marking optimizations.
             * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7046558
             * http://hg.openjdk.java.net/hsx/hotspot-gc/hotspot/rev/842b840e67db
             */
            const unsigned int afterCR7046558 = 22 << 24 | 3;
            if (unlikely(hotSpotVersion < afterCR7046558)) {
                /* Heapstats agent is unsupported G1GC on JDK6. */
                PRINT_CRIT_MSG("Sorry, G1GC isn't supported in this version.");
                PRINT_CRIT_MSG("You should use >= 22.0-b03");
                throw 1;
            }

            if(arg.TimerInterval > 0){
              PRINT_WARN_MSG("Interval SnapShot is not supported with G1GC. Turn off.");
              arg.TimerInterval = 0;
            }

            if(arg.triggerOnDump){
              PRINT_WARN_MSG("SnapShot trigger on dump request is not supported with G1GC. Turn off.");
              arg.triggerOnDump = false;
            }

        }
        
        /* Search common function symbol in libjvm. */
        if (unlikely(!searchCommonFunction())) {
            PRINT_CRIT_MSG("Failure getting java symbol information.");
            throw 1;
        }
        
        /* Create pthred key for klassOop. */
        if (unlikely(pthread_key_create(&oldKlassOopKey,
            pThreadKeyDestructor) != 0)) {
            
            PRINT_CRIT_MSG("Failure create pthread key.");
            throw 1;
        }
    } catch(...) {
        /* Deallocate memory. */
        delete symFinder;
        symFinder = NULL;
        delete vmScanner;
        vmScanner = NULL;
        
        result = false;
    }
    
    return result;
}

/*!
 * \brief Finailization of this util.
 */
void oopUtilFinalize(void) {
    
    /* Cleanup. */
    if(useG1){
      delete checkObjectMap;
      checkObjectMap = NULL;
    }
    
    delete vmScanner;
    vmScanner = NULL;
    
    delete symFinder;
    symFinder = NULL;
    
    pthread_key_delete(oldKlassOopKey);
}

/*!
 * \brief Setup hooking.
 * \warning Please this function call at after Agent_OnLoad.
 * \param funcOnGC     [in] Pointer of GC callback function.
 * \param funcOnCMS    [in] Pointer of CMSGC callback function.
 * \param funcOnJVMTI  [in] Pointer of JVMTI callback function.
 * \param funcOnAdjust [in] Pointer of adjust class callback function.
 * \param funcOnG1GC   [in] Pointer of event callback on G1GC finished.
 * \param maxMemSize   [in] Allocatable maximum memory size of JVM.
 * \return Process result.
 */
bool setupHook(THeapObjectCallback funcOnGC, THeapObjectCallback funcOnCMS,
    THeapObjectCallback funcOnJVMTI, TKlassAdjustCallback funcOnAdjust,
    TCommonCallback funcOnG1GC, size_t maxMemSize) {
    
    /* Set function. */
    gcCallbackFunc       = funcOnGC;
    cmsCallbackFunc      = funcOnCMS;
    jvmtiIteCallbackFunc = funcOnJVMTI;
    adjustCallbackFunc   = funcOnAdjust;
    g1FinishCallbackFunc = funcOnG1GC;
    
    /* Get common function, variable and offset. */
    if (unlikely(!searchCommonInformation())) {
        return false;
    }
    
    /* Get object. */
    collectedHeap = (*(void**)collectedHeap);
    narrowOffsetBase = (ptrdiff_t)*(void**)narrowOffsetBase;
    narrowKlassOffsetBase = (ptrdiff_t)*(void**)narrowKlassOffsetBase;
    
    /* Setup for WatcherThread. */
    if(unlikely(!setupOverrideFunction(watcherThread_hook))){
      PRINT_WARN_MSG("Failure function overriding. func:WatcherThread");
      return false;
    }
    switchOverrideFunction(watcherThread_hook, true);

    /* Setup for JVMTI. */
    if (unlikely(!setupOverrideFunction(jvmti_hook))) {
        
        PRINT_WARN_MSG("Failure function overriding. func:JVMTI");
        return false;
    }
    
    /* Setup for pointer adjustment. */
    if(!enableCR6964458){
      if(unlikely(!setupOverrideFunction(adj_hook))){
        PRINT_WARN_MSG("Failure function overriding. func:adj-ptr");
        return false;
      }
    }
    
    /* Setup by using GC type. */
    
    /* Setup parallel GC and GC by user. */
    if (unlikely(!setupForParallel())) {
        return false;
    }
    
    /* Setup for inner GC function. */
    if (unlikely(!setupOverrideFunction(innerStart_hook))) {
        
        PRINT_WARN_MSG("Failure function overriding. func:common");
        return false;
    }
    
    /* Setup each GC type. */
    bool result = useParallel;
    if(useParOld){
      result = setupForParallelOld();
    }
    else if(useCMS){
      result = setupForCMS();
    }
    else if(useG1){
      result = setupForG1GC(maxMemSize);
    }
    
    return result;
}

/*!
 * \brief Check CMS garbage collector state.
 * \param state        [in]  State of CMS garbage collector.
 * \param needSnapShot [out] Is need snapshot now.
 * \return CMS collector state.
 * \warning Please don't forget call on JVM death.
 */
int checkCMSState(TGCState state, bool *needSnapShot) {
    
    /* Sanity check. */
    if (unlikely(needSnapShot == NULL)) {
        PRINT_WARN_MSG("Illegal paramter!");
        return -1;
    }
    
    static int cmsStateAtStart;
    *needSnapShot = false;
    switch (state) {
        case gcStart:
            /* Call on JVMTI GC start. */
            
            if (*CMS_collectorState <= CMS_INITIALMARKING) {
                
                /* Set stored flag of passed sweep phase. */
                *needSnapShot = needSnapShotByCMSPhase;
                needSnapShotByCMSPhase = false;
                
            } else if (*CMS_collectorState == CMS_FINALMARKING) {
                
                /* switch hooking for CMS new generation. */
                switchOverrideFunction(cms_new_hook, true);
            }
            
            cmsStateAtStart = (*CMS_collectorState);
            isInvokedParallelGC = false;
            break;
            
        case gcFinish:
            /* Call on JVMTI GC finished. */
            switch (*CMS_collectorState) {
                case CMS_MARKING:
                    /* CMS marking phase. */
                    break;
                    
                case CMS_SWEEPING:
                    /* CMS sweep phase. */
                    needSnapShotByCMSPhase = true;
                    
                    break;
                    
                default:
                    /* If called parallel gc. */
                    if (isInvokedParallelGC) {
                        
                        /* GC invoke by user or service without CMS. */
                        (*needSnapShot) = true;
                        needSnapShotByCMSPhase = false;
                        break;
                    }
            }
            
            /* If enable cms new gen hook. */
            if (cmsStateAtStart == CMS_FINALMARKING) {
                /* switch hooking for CMS new generation. */
                switchOverrideFunction(cms_new_hook, false);
            }
            break;
            
        case gcLast:
            /* Call on JVM is terminating. */
            
            /* Set stored flag of passed sweep phase. */
            *needSnapShot = needSnapShotByCMSPhase;
            needSnapShotByCMSPhase = false;
            break;
            
        default:
            /* Not reached here. */
            PRINT_WARN_MSG("Illegal GC state.");
    }

    return *CMS_collectorState;
}

/*!
 * \brief Setup hooking for inner GC event.
 * \warning Please this function call at after Agent_OnLoad.
 * \param enableHook     [in] Flag of enable hooking to function.
 * \param interruptEvent [in] Event callback on many times GC interupt.
 * \return Process result.
 */
bool setupHookForInnerGCEvent(bool enableHook, TCommonCallback interruptEvent) {
    
    isInvokeGCManyTimes = false;
    gcInterruptCallbackFunc = interruptEvent;
    
    return switchOverrideFunction(innerStart_hook, enableHook);
}