1 /*
   2  * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 #include <jni.h>
  24 #include <stdio.h>
  25 
  26 #include <string.h>
  27 #include <jvmti.h>
  28 
  29 #define STATUS_FAILED 2
  30 #define STATUS_PASSED 0
  31 
  32 #define REFERENCES_ARRAY_SIZE 10000000
  33 
  34 #ifndef JNI_ENV_ARG
  35 
  36 #ifdef __cplusplus
  37 #define JNI_ENV_ARG(x, y) x
  38 #define JNI_ENV_PTR(x) x
  39 #else
  40 #define JNI_ENV_ARG(x, y) x , y
  41 #define JNI_ENV_PTR(x) (*x)
  42 #endif
  43 
  44 #endif
  45 
  46 #ifndef _Included_gc_g1_unloading_unloading_classloaders_JNIClassloader
  47 #define _Included_gc_g1_unloading_unloading_classloaders_JNIClassloader
  48 
  49 #ifdef __cplusplus
  50 extern "C" {
  51 #endif
  52 
  53 /*
  54  * Class:     gc_g1_unloading_unloading_classloaders_JNIClassloader
  55  * Method:    loadThroughJNI0
  56  * Signature: (Ljava/lang/String;Ljava/lang/ClassLoader;[B)Ljava/lang/Class;
  57  */
  58 JNIEXPORT jclass JNICALL Java_gc_g1_unloading_classloaders_JNIClassloader_loadThroughJNI0 (JNIEnv * env,
  59                                          jclass clazz, jstring className, jobject classLoader, jbyteArray bytecode) {
  60 
  61   const char * classNameChar = JNI_ENV_PTR(env)->GetStringUTFChars(JNI_ENV_ARG(env, className), NULL);
  62   jbyte * arrayContent = JNI_ENV_PTR(env)->GetByteArrayElements(JNI_ENV_ARG(env, bytecode), NULL);
  63   jsize bytecodeLength = JNI_ENV_PTR(env)->GetArrayLength(JNI_ENV_ARG(env, bytecode));
  64   jclass returnValue = JNI_ENV_PTR(env)->DefineClass(JNI_ENV_ARG(env, classNameChar), classLoader, arrayContent, bytecodeLength);
  65   if (!returnValue) {
  66     printf("ERROR: DefineClass call returned NULL by some reason. Classloading failed.\n");
  67   }
  68 
  69   return returnValue;
  70 }
  71 
  72  /*
  73   * Class:     gc_g1_unloading_unloading_loading_ClassLoadingThread
  74   * Method:    makeRedefinition0
  75   * Signature: (ILjava/lang/Class;[B)I
  76   */
  77 JNIEXPORT jint JNICALL  Java_gc_g1_unloading_loading_ClassLoadingThread_makeRedefinition0(JNIEnv *env,
  78                 jclass cls, jint fl, jclass redefCls, jbyteArray classBytes) {
  79     JavaVM * jvm;
  80     jvmtiEnv * jvmti;
  81     jvmtiError err;
  82     jvmtiCapabilities caps;
  83     jvmtiClassDefinition classDef;
  84     jint jint_err = JNI_ENV_PTR(env)->GetJavaVM(JNI_ENV_ARG(env, &jvm));
  85     if (jint_err) {
  86         printf("GetJavaVM returned nonzero: %d", jint_err);
  87         return STATUS_FAILED;
  88     }
  89 
  90     jint_err = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **)&jvmti), JVMTI_VERSION_1_0);
  91     if (jint_err) {
  92         printf("GetEnv returned nonzero: %d", jint_err);
  93         return STATUS_FAILED;
  94     }
  95 
  96     err = JNI_ENV_PTR(jvmti)->GetPotentialCapabilities(JNI_ENV_ARG(jvmti, &caps));
  97     if (err != JVMTI_ERROR_NONE) {
  98         printf("(GetPotentialCapabilities) unexpected error: %d\n",err);
  99         return JNI_ERR;
 100     }
 101 
 102     err = JNI_ENV_PTR(jvmti)->AddCapabilities(JNI_ENV_ARG(jvmti, &caps));
 103     if (err != JVMTI_ERROR_NONE) {
 104         printf("(AddCapabilities) unexpected error: %d\n", err);
 105         return JNI_ERR;
 106     }
 107 
 108     if (!caps.can_redefine_classes) {
 109         printf("ERROR: Can't redefine classes. jvmtiCapabilities.can_redefine_classes isn't set up.");
 110         return STATUS_FAILED;
 111     }
 112 
 113     classDef.klass = redefCls;
 114     classDef.class_byte_count =
 115         JNI_ENV_PTR(env)->GetArrayLength(JNI_ENV_ARG(env, classBytes));
 116     classDef.class_bytes = (unsigned char *)
 117         JNI_ENV_PTR(env)->GetByteArrayElements(JNI_ENV_ARG(env, classBytes),
 118             NULL);
 119 
 120     if (fl == 2) {
 121         printf(">>>>>>>> Invoke RedefineClasses():\n");
 122         printf("\tnew class byte count=%d\n", classDef.class_byte_count);
 123     }
 124     err = JNI_ENV_PTR(jvmti)->RedefineClasses(JNI_ENV_ARG(jvmti, 1), &classDef);
 125     if (err != JVMTI_ERROR_NONE) {
 126         printf("%s: Failed to call RedefineClasses():\n", __FILE__);
 127         printf("\tthe function returned error %d\n", err);
 128         printf("\tFor more info about this error see the JVMTI spec.\n");
 129         return STATUS_FAILED;
 130     }
 131     if (fl == 2)
 132         printf("<<<<<<<< RedefineClasses() is successfully done\n");
 133 
 134     return STATUS_PASSED;
 135 }
 136 
 137 jobject referencesArray[REFERENCES_ARRAY_SIZE];
 138 int firstFreeIndex = 0;
 139 
 140 /*
 141  * Class:     gc_g1_unloading_unloading_keepref_JNIGlobalRefHolder
 142  * Method:    keepGlobalJNIReference
 143  * Signature: (Ljava/lang/Object;)I
 144  */
 145 JNIEXPORT jint JNICALL Java_gc_g1_unloading_keepref_JNIGlobalRefHolder_keepGlobalJNIReference
 146   (JNIEnv * env, jclass clazz, jobject obj) {
 147     int returnValue;
 148     referencesArray[firstFreeIndex] = JNI_ENV_PTR(env)->NewGlobalRef(JNI_ENV_ARG(env, obj));
 149     printf("checkpoint1 %d \n", firstFreeIndex);
 150     returnValue = firstFreeIndex;
 151     firstFreeIndex++;
 152     return returnValue;
 153 }
 154 
 155 /*
 156  * Class:     gc_g1_unloading_unloading_keepref_JNIGlobalRefHolder
 157  * Method:    deleteGlobalJNIReference
 158  * Signature: (I)V
 159  */
 160 JNIEXPORT void JNICALL Java_gc_g1_unloading_keepref_JNIGlobalRefHolder_deleteGlobalJNIReference
 161   (JNIEnv * env, jclass clazz, jint index) {
 162     JNI_ENV_PTR(env)->DeleteGlobalRef(JNI_ENV_ARG(env, referencesArray[index]));
 163 }
 164 
 165 
 166 /*
 167  * Class:     gc_g1_unloading_unloading_keepref_JNILocalRefHolder
 168  * Method:    holdWithJNILocalReference
 169  * Signature: (Ljava/lang/Object;)V
 170  */
 171 JNIEXPORT void JNICALL Java_gc_g1_unloading_keepref_JNILocalRefHolder_holdWithJNILocalReference
 172   (JNIEnv * env, jobject thisObject, jobject syncObject) {
 173     jclass clazz, objectClazz;
 174     jfieldID objectToKeepField;
 175     jobject objectToKeep, localRef;
 176     jmethodID waitMethod;
 177 
 178     clazz = (*env)->GetObjectClass(env, thisObject);
 179     objectToKeepField = (*env)->GetFieldID(env, clazz, "objectToKeep", "Ljava/lang/Object;");
 180     objectToKeep = (*env)->GetObjectField(env, thisObject, objectToKeepField);
 181     localRef = (*env)->NewLocalRef(env, objectToKeep);
 182     (*env)->SetObjectField(env, thisObject, objectToKeepField, NULL);
 183 
 184     objectClazz = (*env)->FindClass(env, "Ljava/lang/Object;");
 185     waitMethod = (*env)->GetMethodID(env, objectClazz, "wait", "()V");
 186     (*env)->CallVoidMethod(env, syncObject, waitMethod);
 187     printf("checkpoint2 \n");
 188   }
 189 
 190 
 191 #ifdef __cplusplus
 192 }
 193 #endif
 194 #endif