8267796: vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002/TestDescription.java fails with NoClassDefFoundError

Reviewed-by: kevinw, cjplummer
This commit is contained in:
Alex Menkov 2022-03-02 10:54:25 +00:00
parent 12a822a287
commit f12200cd11
4 changed files with 102 additions and 92 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -24,6 +24,7 @@
package nsk.jvmti.scenarios.hotswap.HS201; package nsk.jvmti.scenarios.hotswap.HS201;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.concurrent.CountDownLatch;
import nsk.share.*; import nsk.share.*;
import nsk.share.jvmti.*; import nsk.share.jvmti.*;
@ -73,14 +74,23 @@ public class hs201t002 extends DebugeeClass {
timeout = argHandler.getWaitTime() * 60 * 1000; // milliseconds timeout = argHandler.getWaitTime() * 60 * 1000; // milliseconds
log.display(">>> starting tested thread"); log.display(">>> starting tested thread");
Thread thread = new hs201t002Thread(); hs201t002Thread thread = new hs201t002Thread();
// testing sync // testing sync
status = checkStatus(status); status = checkStatus(status);
setThread(thread);
thread.start(); thread.start();
// setThread(thread) enables JVMTI events, and that can only be done on a live thread,
// so wait until the thread has started.
try {
thread.ready.await();
} catch (InterruptedException e) {
}
setThread(thread);
thread.go.countDown();
while (currentStep != 4) { while (currentStep != 4) {
try { try {
Thread.sleep(100); Thread.sleep(100);
@ -114,6 +124,10 @@ public class hs201t002 extends DebugeeClass {
} }
log.display("Thread suspended in a wrong moment. Retrying..."); log.display("Thread suspended in a wrong moment. Retrying...");
for (int i = 0; i < stackTrace.length; i++) {
log.display("\t" + i + ". " + stackTrace[i]);
}
log.display("Retrying...");
resumeThread(thread); resumeThread(thread);
suspendTry++; suspendTry++;
// Test thread will be suspended at the top of the loop. Let it run for a while. // Test thread will be suspended at the top of the loop. Let it run for a while.
@ -136,12 +150,20 @@ public class hs201t002 extends DebugeeClass {
class hs201t002Thread extends Thread { class hs201t002Thread extends Thread {
CountDownLatch ready = new CountDownLatch(1);
CountDownLatch go = new CountDownLatch(1);
hs201t002Thread() { hs201t002Thread() {
setName("hs201t002Thread"); setName("hs201t002Thread");
} }
public void run() { public void run() {
// run method // run method
ready.countDown();
try {
go.await();
} catch (InterruptedException e) {
}
try { try {
throwException(); throwException();
} catch (Exception e) { } catch (Exception e) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -71,7 +71,7 @@
* newclass * newclass
* *
* @run main/othervm/native * @run main/othervm/native
* -agentlib:hs201t002=pathToNewByteCode=./bin,-waittime=5 * -agentlib:hs201t002=pathToNewByteCode=./bin,-waittime=5,-verbose
* nsk.jvmti.scenarios.hotswap.HS201.hs201t002 * nsk.jvmti.scenarios.hotswap.HS201.hs201t002 -verbose
*/ */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -45,16 +45,18 @@ static jlong timeout = 0;
#define PATH_TO_NEW_BYTECODE "pathToNewByteCode" #define PATH_TO_NEW_BYTECODE "pathToNewByteCode"
static jint testStep; static jint testStep;
static int redefineNumber;
static jint newClassSize;
static unsigned char* newClassBytes;
static jthread testedThread; static jthread testedThread;
static jclass testClass; static jclass testClass;
char chbuffer[255];
const char* getThreadName(JNIEnv* jni_env, jthread thread); // callbackException (isCatch == false) and callbackExceptionCatch (isCatch == true) handler
void handleException(bool isCatch,
jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread,
jmethodID method, jlocation location,
jobject exception);
const char* getThreadName(jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread);
const char* getClassName(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jobject object); const char* getClassName(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jobject object);
int readNewBytecode(jvmtiEnv* jvmti); int readNewBytecode(jvmtiEnv* jvmti, jint *newClassSize, unsigned char* *newClassBytes);
int getLocalVariableValue(jvmtiEnv *jvmti_env, jthread thread, jmethodID method); int getLocalVariableValue(jvmtiEnv *jvmti_env, jthread thread, jmethodID method);
/* ============================================================================= */ /* ============================================================================= */
@ -99,17 +101,19 @@ void disableEvent(jvmtiEnv *jvmti_env, jvmtiEvent event, jthread thread) {
void redefineClass(jvmtiEnv *jvmti_env, jclass klass) { void redefineClass(jvmtiEnv *jvmti_env, jclass klass) {
jvmtiClassDefinition classDef; jvmtiClassDefinition classDef;
char *className; char *className;
jint newClassSize;
unsigned char* newClassBytes;
if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &className, NULL))) { if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &className, NULL))) {
nsk_jvmti_setFailStatus(); nsk_jvmti_setFailStatus();
return; return;
} }
if (!NSK_VERIFY(readNewBytecode(jvmti_env))) { if (!NSK_VERIFY(readNewBytecode(jvmti_env, &newClassSize, &newClassBytes))) {
NSK_COMPLAIN0("TEST FAILED: new bytecode could not be read\n"); NSK_COMPLAIN0("TEST FAILED: new bytecode could not be read\n");
nsk_jvmti_setFailStatus(); nsk_jvmti_setFailStatus();
jvmti_env->Deallocate((unsigned char*)className);
return; return;
} }
@ -121,12 +125,14 @@ void redefineClass(jvmtiEnv *jvmti_env, jclass klass) {
if (!NSK_JVMTI_VERIFY(jvmti_env->RedefineClasses(1, &classDef))) { if (!NSK_JVMTI_VERIFY(jvmti_env->RedefineClasses(1, &classDef))) {
NSK_COMPLAIN1("TEST FAILED: while redefining class %s\n", className); NSK_COMPLAIN1("TEST FAILED: while redefining class %s\n", className);
nsk_jvmti_setFailStatus(); nsk_jvmti_setFailStatus();
return;
} }
if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)className))) { if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)className))) {
nsk_jvmti_setFailStatus(); nsk_jvmti_setFailStatus();
} }
if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate(newClassBytes))) {
nsk_jvmti_setFailStatus();
}
} }
@ -136,7 +142,6 @@ void redefineClass(jvmtiEnv *jvmti_env, jclass klass) {
static void JNICALL static void JNICALL
agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) { agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) {
redefineNumber = 1;
jni = agentJNI; jni = agentJNI;
NSK_DISPLAY0("Waiting for debuggee to become ready\n"); NSK_DISPLAY0("Waiting for debuggee to become ready\n");
@ -144,7 +149,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) {
return; return;
testStep = 1; testStep = 1;
NSK_DISPLAY0("\n\n>>>> Debugge started, waiting for class loading \n"); NSK_DISPLAY0(">>>> Debugge started, waiting for class loading \n");
if (!nsk_jvmti_resumeSync()) if (!nsk_jvmti_resumeSync())
return; return;
@ -183,27 +188,20 @@ callbackClassLoad(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
jclass klass) { jclass klass) {
char *className; char *className;
char *generic;
if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &className, &generic))) { if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &className, NULL))) {
nsk_jvmti_setFailStatus(); nsk_jvmti_setFailStatus();
return; return;
} }
if (strcmp(className, EXPECTED_CLASS_SIGN) == 0) { if (strcmp(className, EXPECTED_CLASS_SIGN) == 0) {
NSK_DISPLAY1("\n\n>>>> Class loaded: %s", className); NSK_DISPLAY1(">>>> Class loaded: %s, activating breakpoint\n", className);
NSK_DISPLAY0(", activating breakpoint\n");
setBreakPoint(jvmti_env, jni_env, klass); setBreakPoint(jvmti_env, jni_env, klass);
} }
if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)className))) { if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)className))) {
nsk_jvmti_setFailStatus(); nsk_jvmti_setFailStatus();
} }
if (generic != NULL)
if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)generic))) {
nsk_jvmti_setFailStatus();
}
} }
/* ============================================================================= */ /* ============================================================================= */
@ -216,7 +214,7 @@ JNIEXPORT void JNICALL
callbackBreakpoint(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, callbackBreakpoint(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
jmethodID method, jlocation location) { jmethodID method, jlocation location) {
NSK_DISPLAY0("\n\n>>>>Breakpoint fired, enabling SINGLE_STEP\n"); NSK_DISPLAY0(">>>>Breakpoint fired, enabling SINGLE_STEP\n");
enableEvent(jvmti_env, JVMTI_EVENT_SINGLE_STEP, thread); enableEvent(jvmti_env, JVMTI_EVENT_SINGLE_STEP, thread);
} }
@ -266,7 +264,7 @@ callbackSingleStep(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
case 2: case 2:
NSK_DISPLAY1("\n\n>>>> Checking if redefined method is not obsolete\n", testStep); NSK_DISPLAY1(">>>> Checking if redefined method is not obsolete\n", testStep);
if (!NSK_JVMTI_VERIFY(jvmti->IsMethodObsolete(method, &is_obsolete))) { if (!NSK_JVMTI_VERIFY(jvmti->IsMethodObsolete(method, &is_obsolete))) {
NSK_COMPLAIN0("TEST FAILED: unable to check method to be obsolete\n"); NSK_COMPLAIN0("TEST FAILED: unable to check method to be obsolete\n");
@ -283,7 +281,7 @@ callbackSingleStep(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
case 3: case 3:
NSK_DISPLAY1("\n\n>>>> Popping the currently executing frame\n", testStep); NSK_DISPLAY1(">>>> Popping the currently executing frame\n", testStep);
testStep++; testStep++;
setCurrentStep(jni_env, testStep); setCurrentStep(jni_env, testStep);
@ -292,7 +290,7 @@ callbackSingleStep(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
case 5: case 5:
if (value < 10) { if (value < 10) {
NSK_DISPLAY1("\n\n>>>> Disabling single step\n", testStep); NSK_DISPLAY1(">>>> Disabling single step\n", testStep);
disableEvent(jvmti_env, JVMTI_EVENT_SINGLE_STEP, thread); disableEvent(jvmti_env, JVMTI_EVENT_SINGLE_STEP, thread);
setCurrentStep(jni_env, testStep); setCurrentStep(jni_env, testStep);
} }
@ -302,7 +300,7 @@ callbackSingleStep(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
} }
if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*) declaringClassName))) { if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*) declaringClassName))) {
NSK_COMPLAIN0("TEST FAILED: unable to deallocate memory pointed to method name\n\n"); NSK_COMPLAIN0("TEST FAILED: unable to deallocate memory pointed to declaringClassName\n\n");
} }
} }
@ -324,24 +322,7 @@ callbackException(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
jmethodID method, jlocation location, jobject exception, jmethodID method, jlocation location, jobject exception,
jmethodID catch_method, jlocation catch_location) { jmethodID catch_method, jlocation catch_location) {
const char *className; handleException(false, jvmti_env, jni_env, thread, method, location, exception);
className = getClassName(jvmti_env, jni_env, exception);
if (strcmp(EXPECTED_CLASS_SIGN, className) == 0) {
jclass klass;
NSK_DISPLAY2("\n\n>>>> Exception %s in thread - %s\n",
className, getThreadName(jni_env, thread));
testStep++;
if (!NSK_JNI_VERIFY(jni_env, (klass = jni_env->GetObjectClass(exception)) != NULL)) {
nsk_jvmti_setFailStatus();
return;
}
redefineClass(jvmti_env, klass);
}
} }
/* ============================================================================= */ /* ============================================================================= */
@ -355,15 +336,27 @@ callbackExceptionCatch(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
jmethodID method, jlocation location, jmethodID method, jlocation location,
jobject exception) { jobject exception) {
const char *className; handleException(true, jvmti_env, jni_env, thread, method, location, exception);
}
className = getClassName(jvmti_env, jni_env, exception); /* ============================================================================= */
if (strcmp(EXPECTED_CLASS_SIGN, className) == 0) { void handleException(bool isCatch,
jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread,
jmethodID method, jlocation location,
jobject exception) {
const char* className = getClassName(jvmti_env, jni_env, exception);
if (className != NULL && strcmp(EXPECTED_CLASS_SIGN, className) == 0) {
jclass klass; jclass klass;
NSK_DISPLAY2("\n\n>>>> Caught exception %s in thread - %s\n", const char* threadName = getThreadName(jvmti_env, jni_env, thread);
className, getThreadName(jni_env, thread)); NSK_DISPLAY3(">>>> %s %s in thread - %s\n", isCatch ? "Caught exception" : "Exception",
className, threadName != NULL ? threadName : "NULL");
jvmti->Deallocate((unsigned char*)className);
if (threadName != NULL) {
jvmti->Deallocate((unsigned char*)threadName);
}
testStep++; testStep++;
if (!NSK_JNI_VERIFY(jni_env, (klass = jni_env->GetObjectClass(exception)) != NULL)) { if (!NSK_JNI_VERIFY(jni_env, (klass = jni_env->GetObjectClass(exception)) != NULL)) {
@ -373,11 +366,11 @@ callbackExceptionCatch(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
redefineClass(jvmti_env, klass); redefineClass(jvmti_env, klass);
} }
} }
/* ============================================================================= */
int readNewBytecode(jvmtiEnv* jvmti) { int readNewBytecode(jvmtiEnv* jvmti, jint *newClassSize, unsigned char* *newClassBytes) {
char filename[256]; char filename[256];
FILE *bytecode; FILE *bytecode;
@ -403,17 +396,19 @@ int readNewBytecode(jvmtiEnv* jvmti) {
} }
fseek(bytecode, 0, SEEK_END); fseek(bytecode, 0, SEEK_END);
newClassSize = ftell(bytecode); *newClassSize = ftell(bytecode);
rewind(bytecode); rewind(bytecode);
if (!NSK_JVMTI_VERIFY(jvmti->Allocate(newClassSize, &newClassBytes))) { if (!NSK_JVMTI_VERIFY(jvmti->Allocate(*newClassSize, newClassBytes))) {
NSK_COMPLAIN0("buffer couldn't be allocated\n"); NSK_COMPLAIN0("buffer couldn't be allocated\n");
return NSK_FALSE; return NSK_FALSE;
} }
read_bytes = (jint) fread(newClassBytes, 1, newClassSize, bytecode); read_bytes = (jint) fread(*newClassBytes, 1, *newClassSize, bytecode);
fclose(bytecode); fclose(bytecode);
if (read_bytes != newClassSize) { if (read_bytes != *newClassSize) {
NSK_COMPLAIN0("TEST FAILED: error reading file\n"); NSK_COMPLAIN0("TEST FAILED: error reading file\n");
jvmti->Deallocate(*newClassBytes);
*newClassBytes = NULL;
return NSK_FALSE; return NSK_FALSE;
} }
@ -422,34 +417,41 @@ int readNewBytecode(jvmtiEnv* jvmti) {
/* ============================================================================= */ /* ============================================================================= */
const char* getThreadName(JNIEnv* jni_env, jthread thread) { const char* getThreadName(jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread) {
jmethodID methodID; jmethodID methodID;
jclass klass; jclass klass;
jstring jthreadName; jstring jthreadName;
jsize jthreadNameLen;
unsigned char *result = NULL;
const char *threadName; const char *threadName;
strcpy(chbuffer, "");
if (!NSK_JNI_VERIFY(jni_env, (klass = jni_env->GetObjectClass(thread)) != NULL)) { if (!NSK_JNI_VERIFY(jni_env, (klass = jni_env->GetObjectClass(thread)) != NULL)) {
nsk_jvmti_setFailStatus(); nsk_jvmti_setFailStatus();
return chbuffer; return NULL;
} }
if (!NSK_JNI_VERIFY(jni_env, (methodID = if (!NSK_JNI_VERIFY(jni_env, (methodID =
jni_env->GetMethodID(klass, "getName", "()Ljava/lang/String;")) != NULL)) { jni_env->GetMethodID(klass, "getName", "()Ljava/lang/String;")) != NULL)) {
nsk_jvmti_setFailStatus(); nsk_jvmti_setFailStatus();
return chbuffer; return NULL;
} }
jthreadName = (jstring) jni_env->CallObjectMethod(thread, methodID); jthreadName = (jstring) jni_env->CallObjectMethod(thread, methodID);
jthreadNameLen = jni_env->GetStringUTFLength(jthreadName);
if (!NSK_JVMTI_VERIFY(jvmti_env->Allocate(jthreadNameLen + 1, &result))) {
NSK_COMPLAIN0("buffer couldn't be allocated\n");
return NULL;
}
threadName = jni_env->GetStringUTFChars(jthreadName, 0); threadName = jni_env->GetStringUTFChars(jthreadName, 0);
strcpy(chbuffer, threadName); memcpy(result, threadName, jthreadNameLen + 1);
jni_env->ReleaseStringUTFChars(jthreadName, threadName); jni_env->ReleaseStringUTFChars(jthreadName, threadName);
return chbuffer; return (char*)result;
} }
/* ============================================================================= */ /* ============================================================================= */
@ -457,33 +459,19 @@ const char* getThreadName(JNIEnv* jni_env, jthread thread) {
const char* getClassName(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jobject object) { const char* getClassName(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jobject object) {
char *className; char *className;
char *generic;
jclass klass; jclass klass;
strcpy(chbuffer, "");
if (!NSK_JNI_VERIFY(jni_env, (klass = jni_env->GetObjectClass(object)) != NULL)) { if (!NSK_JNI_VERIFY(jni_env, (klass = jni_env->GetObjectClass(object)) != NULL)) {
nsk_jvmti_setFailStatus(); nsk_jvmti_setFailStatus();
return chbuffer; return NULL;
} }
if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &className, &generic))) { if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &className, NULL))) {
nsk_jvmti_setFailStatus(); nsk_jvmti_setFailStatus();
return chbuffer; return NULL;
} }
strcpy(chbuffer, className); return className;
if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)className))) {
nsk_jvmti_setFailStatus();
}
if (generic != NULL)
if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)generic))) {
nsk_jvmti_setFailStatus();
}
return chbuffer;
} }
/* ============================================================================= */ /* ============================================================================= */
@ -546,6 +534,10 @@ Java_nsk_jvmti_scenarios_hotswap_HS201_hs201t002_setThread(JNIEnv *env,
if (!NSK_JNI_VERIFY(env, (testedThread = env->NewGlobalRef(thread)) != NULL)) if (!NSK_JNI_VERIFY(env, (testedThread = env->NewGlobalRef(thread)) != NULL))
nsk_jvmti_setFailStatus(); nsk_jvmti_setFailStatus();
enableEvent(jvmti, JVMTI_EVENT_CLASS_LOAD, testedThread);
enableEvent(jvmti, JVMTI_EVENT_BREAKPOINT, testedThread);
enableEvent(jvmti, JVMTI_EVENT_EXCEPTION, testedThread);
enableEvent(jvmti, JVMTI_EVENT_EXCEPTION_CATCH, testedThread);
} }
/* ============================================================================= */ /* ============================================================================= */
@ -665,11 +657,6 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
NSK_DISPLAY0("Enable events\n"); NSK_DISPLAY0("Enable events\n");
enableEvent(jvmti, JVMTI_EVENT_CLASS_LOAD, testedThread);
enableEvent(jvmti, JVMTI_EVENT_BREAKPOINT, testedThread);
enableEvent(jvmti, JVMTI_EVENT_EXCEPTION, testedThread);
enableEvent(jvmti, JVMTI_EVENT_EXCEPTION_CATCH, testedThread);
if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
return JNI_ERR; return JNI_ERR;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -26,6 +26,7 @@ package nsk.jvmti.scenarios.hotswap.HS201;
public class hs201t002a extends Exception { public class hs201t002a extends Exception {
public hs201t002a () { public hs201t002a () {
System.out.println("Current step: " + hs201t002.currentStep); // Avoid calling classloader to find hs201t002 in doInit()
doInit(); doInit();
} }