Merge
This commit is contained in:
commit
d7f9269527
@ -3619,13 +3619,14 @@ bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
|
||||
"possibility of dangling Thread pointer");
|
||||
|
||||
OSThread* osthread = thread->osthread();
|
||||
bool interrupted = osthread->interrupted();
|
||||
// There is no synchronization between the setting of the interrupt
|
||||
// and it being cleared here. It is critical - see 6535709 - that
|
||||
// we only clear the interrupt state, and reset the interrupt event,
|
||||
// if we are going to report that we were indeed interrupted - else
|
||||
// an interrupt can be "lost", leading to spurious wakeups or lost wakeups
|
||||
// depending on the timing
|
||||
// depending on the timing. By checking thread interrupt event to see
|
||||
// if the thread gets real interrupt thus prevent spurious wakeup.
|
||||
bool interrupted = osthread->interrupted() && (WaitForSingleObject(osthread->interrupt_event(), 0) == WAIT_OBJECT_0);
|
||||
if (interrupted && clear_interrupted) {
|
||||
osthread->set_interrupted(false);
|
||||
ResetEvent(osthread->interrupt_event());
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -273,8 +273,8 @@ class DebugInfoReadStream : public CompressedReadStream {
|
||||
}
|
||||
Method* read_method() {
|
||||
Method* o = (Method*)(code()->metadata_at(read_int()));
|
||||
assert(o == NULL ||
|
||||
o->is_metaspace_object(), "meta data only");
|
||||
// is_metadata() is a faster check than is_metaspace_object()
|
||||
assert(o == NULL || o->is_metadata(), "meta data only");
|
||||
return o;
|
||||
}
|
||||
ScopeValue* read_object_value();
|
||||
|
@ -1295,6 +1295,7 @@ void ConstantPool::copy_entry_to(constantPoolHandle from_cp, int from_i,
|
||||
} break;
|
||||
|
||||
case JVM_CONSTANT_UnresolvedClass:
|
||||
case JVM_CONSTANT_UnresolvedClassInError:
|
||||
{
|
||||
// Can be resolved after checking tag, so check the slot first.
|
||||
CPSlot entry = from_cp->slot_at(from_i);
|
||||
|
@ -42,6 +42,7 @@ class Metadata : public MetaspaceObj {
|
||||
// Rehashing support for tables containing pointers to this
|
||||
unsigned int new_hash(juint seed) { ShouldNotReachHere(); return 0; }
|
||||
|
||||
virtual bool is_metadata() const volatile { return true; }
|
||||
virtual bool is_klass() const volatile { return false; }
|
||||
virtual bool is_method() const volatile { return false; }
|
||||
virtual bool is_methodData() const volatile { return false; }
|
||||
|
@ -3180,7 +3180,8 @@ bool LibraryCallKit::inline_native_currentThread() {
|
||||
// private native boolean java.lang.Thread.isInterrupted(boolean ClearInterrupted);
|
||||
bool LibraryCallKit::inline_native_isInterrupted() {
|
||||
// Add a fast path to t.isInterrupted(clear_int):
|
||||
// (t == Thread.current() && (!TLS._osthread._interrupted || !clear_int))
|
||||
// (t == Thread.current() &&
|
||||
// (!TLS._osthread._interrupted || WINDOWS_ONLY(false) NOT_WINDOWS(!clear_int)))
|
||||
// ? TLS._osthread._interrupted : /*slow path:*/ t.isInterrupted(clear_int)
|
||||
// So, in the common case that the interrupt bit is false,
|
||||
// we avoid making a call into the VM. Even if the interrupt bit
|
||||
@ -3237,6 +3238,7 @@ bool LibraryCallKit::inline_native_isInterrupted() {
|
||||
// drop through to next case
|
||||
set_control( _gvn.transform(new (C) IfTrueNode(iff_bit)));
|
||||
|
||||
#ifndef TARGET_OS_FAMILY_windows
|
||||
// (c) Or, if interrupt bit is set and clear_int is false, use 2nd fast path.
|
||||
Node* clr_arg = argument(1);
|
||||
Node* cmp_arg = _gvn.transform(new (C) CmpINode(clr_arg, intcon(0)));
|
||||
@ -3250,6 +3252,10 @@ bool LibraryCallKit::inline_native_isInterrupted() {
|
||||
|
||||
// drop through to next case
|
||||
set_control( _gvn.transform(new (C) IfTrueNode(iff_arg)));
|
||||
#else
|
||||
// To return true on Windows you must read the _interrupted field
|
||||
// and check the the event state i.e. take the slow path.
|
||||
#endif // TARGET_OS_FAMILY_windows
|
||||
|
||||
// (d) Otherwise, go to the slow path.
|
||||
slow_region->add_req(control());
|
||||
|
@ -4360,7 +4360,7 @@ JVM_END
|
||||
|
||||
JVM_ENTRY(void, JVM_GetVersionInfo(JNIEnv* env, jvm_version_info* info, size_t info_size))
|
||||
{
|
||||
memset(info, 0, sizeof(info_size));
|
||||
memset(info, 0, info_size);
|
||||
|
||||
info->jvm_version = Abstract_VM_Version::jvm_version();
|
||||
info->update_version = 0; /* 0 in HotSpot Express VM */
|
||||
|
@ -1464,7 +1464,19 @@ JvmtiEnv::PopFrame(JavaThread* java_thread) {
|
||||
// It's fine to update the thread state here because no JVMTI events
|
||||
// shall be posted for this PopFrame.
|
||||
|
||||
// It is only safe to perform the direct operation on the current
|
||||
// thread. All other usage needs to use a vm-safepoint-op for safety.
|
||||
if (java_thread == JavaThread::current()) {
|
||||
state->update_for_pop_top_frame();
|
||||
} else {
|
||||
VM_UpdateForPopTopFrame op(state);
|
||||
VMThread::execute(&op);
|
||||
jvmtiError err = op.result();
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
java_thread->set_popframe_condition(JavaThread::popframe_pending_bit);
|
||||
// Set pending step flag for this popframe and it is cleared when next
|
||||
// step event is posted.
|
||||
@ -1505,6 +1517,7 @@ JvmtiEnv::GetFrameLocation(JavaThread* java_thread, jint depth, jmethodID* metho
|
||||
// depth - pre-checked as non-negative
|
||||
jvmtiError
|
||||
JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) {
|
||||
jvmtiError err = JVMTI_ERROR_NONE;
|
||||
ResourceMark rm;
|
||||
uint32_t debug_bits = 0;
|
||||
|
||||
@ -1532,10 +1545,17 @@ JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) {
|
||||
|
||||
assert(vf->frame_pointer() != NULL, "frame pointer mustn't be NULL");
|
||||
|
||||
// It is only safe to perform the direct operation on the current
|
||||
// thread. All other usage needs to use a vm-safepoint-op for safety.
|
||||
if (java_thread == JavaThread::current()) {
|
||||
int frame_number = state->count_frames() - depth;
|
||||
state->env_thread_state(this)->set_frame_pop(frame_number);
|
||||
|
||||
return JVMTI_ERROR_NONE;
|
||||
} else {
|
||||
VM_SetFramePop op(this, state, depth);
|
||||
VMThread::execute(&op);
|
||||
err = op.result();
|
||||
}
|
||||
return err;
|
||||
} /* end NotifyFramePop */
|
||||
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "prims/jvmtiEnvThreadState.hpp"
|
||||
#include "prims/jvmtiEventController.hpp"
|
||||
#include "prims/jvmtiThreadState.hpp"
|
||||
#include "prims/jvmtiThreadState.inline.hpp"
|
||||
#include "runtime/fieldDescriptor.hpp"
|
||||
#include "runtime/frame.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
@ -334,6 +335,60 @@ class JvmtiEnvIterator : public StackObj {
|
||||
JvmtiEnv* next(JvmtiEnvBase* env) { return env->next_environment(); }
|
||||
};
|
||||
|
||||
// VM operation to update for pop top frame.
|
||||
class VM_UpdateForPopTopFrame : public VM_Operation {
|
||||
private:
|
||||
JvmtiThreadState* _state;
|
||||
jvmtiError _result;
|
||||
|
||||
public:
|
||||
VM_UpdateForPopTopFrame(JvmtiThreadState* state) {
|
||||
_state = state;
|
||||
_result = JVMTI_ERROR_NONE;
|
||||
}
|
||||
VMOp_Type type() const { return VMOp_UpdateForPopTopFrame; }
|
||||
jvmtiError result() { return _result; }
|
||||
void doit() {
|
||||
JavaThread* jt = _state->get_thread();
|
||||
if (Threads::includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
|
||||
_state->update_for_pop_top_frame();
|
||||
} else {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// VM operation to set frame pop.
|
||||
class VM_SetFramePop : public VM_Operation {
|
||||
private:
|
||||
JvmtiEnv *_env;
|
||||
JvmtiThreadState* _state;
|
||||
jint _depth;
|
||||
jvmtiError _result;
|
||||
|
||||
public:
|
||||
VM_SetFramePop(JvmtiEnv *env, JvmtiThreadState* state, jint depth) {
|
||||
_env = env;
|
||||
_state = state;
|
||||
_depth = depth;
|
||||
_result = JVMTI_ERROR_NONE;
|
||||
}
|
||||
// Nested operation must be allowed for the VM_EnterInterpOnlyMode that is
|
||||
// called from the JvmtiEventControllerPrivate::recompute_thread_enabled.
|
||||
bool allow_nested_vm_operations() const { return true; }
|
||||
VMOp_Type type() const { return VMOp_SetFramePop; }
|
||||
jvmtiError result() { return _result; }
|
||||
void doit() {
|
||||
JavaThread* jt = _state->get_thread();
|
||||
if (Threads::includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
|
||||
int frame_number = _state->count_frames() - _depth;
|
||||
_state->env_thread_state((JvmtiEnvBase*)_env)->set_frame_pop(frame_number);
|
||||
} else {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// VM operation to get monitor information with stack depth.
|
||||
class VM_GetOwnedMonitorInfo : public VM_Operation {
|
||||
|
@ -190,12 +190,8 @@ void JvmtiEnvThreadState::compare_and_set_current_location(Method* new_method,
|
||||
|
||||
|
||||
JvmtiFramePops* JvmtiEnvThreadState::get_frame_pops() {
|
||||
#ifdef ASSERT
|
||||
uint32_t debug_bits = 0;
|
||||
#endif
|
||||
assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
|
||||
"frame pop data only accessible from same thread or while suspended");
|
||||
|
||||
assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
|
||||
"frame pop data only accessible from same thread or at safepoint");
|
||||
if (_frame_pops == NULL) {
|
||||
_frame_pops = new JvmtiFramePops();
|
||||
assert(_frame_pops != NULL, "_frame_pops != NULL");
|
||||
@ -209,44 +205,32 @@ bool JvmtiEnvThreadState::has_frame_pops() {
|
||||
}
|
||||
|
||||
void JvmtiEnvThreadState::set_frame_pop(int frame_number) {
|
||||
#ifdef ASSERT
|
||||
uint32_t debug_bits = 0;
|
||||
#endif
|
||||
assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
|
||||
"frame pop data only accessible from same thread or while suspended");
|
||||
assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
|
||||
"frame pop data only accessible from same thread or at safepoint");
|
||||
JvmtiFramePop fpop(frame_number);
|
||||
JvmtiEventController::set_frame_pop(this, fpop);
|
||||
}
|
||||
|
||||
|
||||
void JvmtiEnvThreadState::clear_frame_pop(int frame_number) {
|
||||
#ifdef ASSERT
|
||||
uint32_t debug_bits = 0;
|
||||
#endif
|
||||
assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
|
||||
"frame pop data only accessible from same thread or while suspended");
|
||||
assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
|
||||
"frame pop data only accessible from same thread or at safepoint");
|
||||
JvmtiFramePop fpop(frame_number);
|
||||
JvmtiEventController::clear_frame_pop(this, fpop);
|
||||
}
|
||||
|
||||
|
||||
void JvmtiEnvThreadState::clear_to_frame_pop(int frame_number) {
|
||||
#ifdef ASSERT
|
||||
uint32_t debug_bits = 0;
|
||||
#endif
|
||||
assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
|
||||
"frame pop data only accessible from same thread or while suspended");
|
||||
assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
|
||||
"frame pop data only accessible from same thread or at safepoint");
|
||||
JvmtiFramePop fpop(frame_number);
|
||||
JvmtiEventController::clear_to_frame_pop(this, fpop);
|
||||
}
|
||||
|
||||
|
||||
bool JvmtiEnvThreadState::is_frame_pop(int cur_frame_number) {
|
||||
#ifdef ASSERT
|
||||
uint32_t debug_bits = 0;
|
||||
#endif
|
||||
assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
|
||||
"frame pop data only accessible from same thread or while suspended");
|
||||
assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
|
||||
"frame pop data only accessible from same thread or at safepoint");
|
||||
if (!get_thread()->is_interp_only_mode() || _frame_pops == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -989,21 +989,21 @@ JvmtiEventController::set_extension_event_callback(JvmtiEnvBase *env,
|
||||
|
||||
void
|
||||
JvmtiEventController::set_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
|
||||
MutexLocker mu(JvmtiThreadState_lock);
|
||||
MutexLockerEx mu(SafepointSynchronize::is_at_safepoint() ? NULL : JvmtiThreadState_lock);
|
||||
JvmtiEventControllerPrivate::set_frame_pop(ets, fpop);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JvmtiEventController::clear_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
|
||||
MutexLocker mu(JvmtiThreadState_lock);
|
||||
MutexLockerEx mu(SafepointSynchronize::is_at_safepoint() ? NULL : JvmtiThreadState_lock);
|
||||
JvmtiEventControllerPrivate::clear_frame_pop(ets, fpop);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JvmtiEventController::clear_to_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
|
||||
MutexLocker mu(JvmtiThreadState_lock);
|
||||
MutexLockerEx mu(SafepointSynchronize::is_at_safepoint() ? NULL : JvmtiThreadState_lock);
|
||||
JvmtiEventControllerPrivate::clear_to_frame_pop(ets, fpop);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -63,6 +63,7 @@ JvmtiThreadState::JvmtiThreadState(JavaThread* thread)
|
||||
_vm_object_alloc_event_collector = NULL;
|
||||
_the_class_for_redefinition_verification = NULL;
|
||||
_scratch_class_for_redefinition_verification = NULL;
|
||||
_cur_stack_depth = UNKNOWN_STACK_DEPTH;
|
||||
|
||||
// JVMTI ForceEarlyReturn support
|
||||
_pending_step_for_earlyret = false;
|
||||
@ -213,12 +214,9 @@ void JvmtiThreadState::leave_interp_only_mode() {
|
||||
|
||||
// Helper routine used in several places
|
||||
int JvmtiThreadState::count_frames() {
|
||||
#ifdef ASSERT
|
||||
uint32_t debug_bits = 0;
|
||||
#endif
|
||||
assert(SafepointSynchronize::is_at_safepoint() ||
|
||||
JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
|
||||
"at safepoint or must be suspended");
|
||||
guarantee(SafepointSynchronize::is_at_safepoint() ||
|
||||
(JavaThread *)Thread::current() == get_thread(),
|
||||
"must be current thread or at safepoint");
|
||||
|
||||
if (!get_thread()->has_last_Java_frame()) return 0; // no Java frames
|
||||
|
||||
@ -243,15 +241,9 @@ int JvmtiThreadState::count_frames() {
|
||||
|
||||
|
||||
void JvmtiThreadState::invalidate_cur_stack_depth() {
|
||||
Thread *cur = Thread::current();
|
||||
uint32_t debug_bits = 0;
|
||||
|
||||
// The caller can be the VMThread at a safepoint, the current thread
|
||||
// or the target thread must be suspended.
|
||||
guarantee((cur->is_VM_thread() && SafepointSynchronize::is_at_safepoint()) ||
|
||||
(JavaThread *)cur == get_thread() ||
|
||||
JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
|
||||
"sanity check");
|
||||
guarantee(SafepointSynchronize::is_at_safepoint() ||
|
||||
(JavaThread *)Thread::current() == get_thread(),
|
||||
"must be current thread or at safepoint");
|
||||
|
||||
_cur_stack_depth = UNKNOWN_STACK_DEPTH;
|
||||
}
|
||||
@ -280,10 +272,9 @@ void JvmtiThreadState::decr_cur_stack_depth() {
|
||||
}
|
||||
|
||||
int JvmtiThreadState::cur_stack_depth() {
|
||||
uint32_t debug_bits = 0;
|
||||
guarantee(JavaThread::current() == get_thread() ||
|
||||
JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
|
||||
"must be current thread or suspended");
|
||||
guarantee(SafepointSynchronize::is_at_safepoint() ||
|
||||
(JavaThread *)Thread::current() == get_thread(),
|
||||
"must be current thread or at safepoint");
|
||||
|
||||
if (!is_interp_only_mode() || _cur_stack_depth == UNKNOWN_STACK_DEPTH) {
|
||||
_cur_stack_depth = count_frames();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -74,6 +74,8 @@
|
||||
template(PopulateDumpSharedSpace) \
|
||||
template(JNIFunctionTableCopier) \
|
||||
template(RedefineClasses) \
|
||||
template(UpdateForPopTopFrame) \
|
||||
template(SetFramePop) \
|
||||
template(GetOwnedMonitorInfo) \
|
||||
template(GetObjectMonitorUsage) \
|
||||
template(GetCurrentContendedMonitor) \
|
||||
|
@ -25,7 +25,7 @@
|
||||
* @test
|
||||
* @bug 6294277
|
||||
* @summary java -Xdebug crashes on SourceDebugExtension attribute larger than 64K
|
||||
* @run main/othervm -Xdebug -Xrunjdwp:transport=dt_socket,address=8888,server=y,suspend=n SourceDebugExtension
|
||||
* @run main/othervm -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n SourceDebugExtension
|
||||
*/
|
||||
import java.io.*;
|
||||
|
||||
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Redefine a class with an UnresolvedClass reference in the constant pool.
|
||||
* @bug 8035150
|
||||
* @library /testlibrary
|
||||
* @build UnresolvedClassAgent com.oracle.java.testlibrary.ProcessTools com.oracle.java.testlibrary.OutputAnalyzer
|
||||
* @run main TestRedefineWithUnresolvedClass
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.oracle.java.testlibrary.OutputAnalyzer;
|
||||
import com.oracle.java.testlibrary.ProcessTools;
|
||||
|
||||
public class TestRedefineWithUnresolvedClass {
|
||||
|
||||
final static String slash = File.separator;
|
||||
final static String testClasses = System.getProperty("test.classes") + slash;
|
||||
|
||||
public static void main(String... args) throws Throwable {
|
||||
// delete this class to cause a NoClassDefFoundError
|
||||
File unresolved = new File(testClasses, "MyUnresolvedClass.class");
|
||||
if (unresolved.exists() && !unresolved.delete()) {
|
||||
throw new Exception("Could not delete: " + unresolved);
|
||||
}
|
||||
|
||||
// build the javaagent
|
||||
buildJar("UnresolvedClassAgent");
|
||||
|
||||
// launch a VM with the javaagent
|
||||
launchTest();
|
||||
}
|
||||
|
||||
private static void buildJar(String jarName) throws Throwable {
|
||||
String testSrc = System.getProperty("test.src", "?") + slash;
|
||||
|
||||
String jarPath = String.format("%s%s.jar", testClasses, jarName);
|
||||
String manifestPath = String.format("%s%s.mf", testSrc, jarName);
|
||||
String className = String.format("%s.class", jarName);
|
||||
|
||||
String[] args = new String[] {"-cfm", jarPath, manifestPath, "-C", testClasses, className};
|
||||
|
||||
System.out.println("Running jar " + Arrays.toString(args));
|
||||
sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
|
||||
if (!jarTool.run(args)) {
|
||||
throw new Exception("jar failed: args=" + Arrays.toString(args));
|
||||
}
|
||||
}
|
||||
|
||||
private static void launchTest() throws Throwable {
|
||||
String[] args = {
|
||||
"-javaagent:" + testClasses + "UnresolvedClassAgent.jar",
|
||||
"-Dtest.classes=" + testClasses,
|
||||
"UnresolvedClassAgent" };
|
||||
OutputAnalyzer output = ProcessTools.executeTestJvm(args);
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
}
|
69
hotspot/test/serviceability/jvmti/UnresolvedClassAgent.java
Normal file
69
hotspot/test/serviceability/jvmti/UnresolvedClassAgent.java
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.lang.instrument.ClassDefinition;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
|
||||
/*
|
||||
* This class is present during compilation, but will be deleted before execution.
|
||||
*/
|
||||
class MyUnresolvedClass {
|
||||
static void bar() {
|
||||
}
|
||||
}
|
||||
|
||||
class MyRedefinedClass {
|
||||
static void foo() {
|
||||
MyUnresolvedClass.bar();
|
||||
}
|
||||
}
|
||||
|
||||
public class UnresolvedClassAgent {
|
||||
public static void main(String... args) {
|
||||
}
|
||||
|
||||
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||
try {
|
||||
MyRedefinedClass.foo();
|
||||
} catch(NoClassDefFoundError err) {
|
||||
System.out.println("NoClassDefFoundError (expected)");
|
||||
}
|
||||
|
||||
File f = new File(System.getProperty("test.classes"), "MyRedefinedClass.class");
|
||||
byte[] buf = new byte[(int)f.length()];
|
||||
try (DataInputStream dis = new DataInputStream(new FileInputStream(f))) {
|
||||
dis.readFully(buf);
|
||||
}
|
||||
ClassDefinition cd = new ClassDefinition(MyRedefinedClass.class, buf);
|
||||
inst.redefineClasses(new ClassDefinition[] {cd});
|
||||
|
||||
try {
|
||||
MyRedefinedClass.foo();
|
||||
} catch(NoClassDefFoundError err) {
|
||||
System.out.println("NoClassDefFoundError (expected again)");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
Premain-Class: UnresolvedClassAgent
|
||||
Can-Redefine-Classes: true
|
@ -163,10 +163,87 @@ public final class ProcessTools {
|
||||
|
||||
// Reporting
|
||||
StringBuilder cmdLine = new StringBuilder();
|
||||
for (String cmd : args)
|
||||
for (String cmd : args) {
|
||||
cmdLine.append(cmd).append(' ');
|
||||
}
|
||||
System.out.println("Command line: [" + cmdLine.toString() + "]");
|
||||
|
||||
return new ProcessBuilder(args.toArray(new String[args.size()]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a test jvm process, waits for it to finish and returns the process output.
|
||||
* The default jvm options from jtreg, test.vm.opts and test.java.opts, are added.
|
||||
* The java from the test.jdk is used to execute the command.
|
||||
*
|
||||
* The command line will be like:
|
||||
* {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds
|
||||
*
|
||||
* @param cmds User specifed arguments.
|
||||
* @return The output from the process.
|
||||
*/
|
||||
public static OutputAnalyzer executeTestJvm(String... cmds) throws Throwable {
|
||||
ProcessBuilder pb = createJavaProcessBuilder(Utils.addTestJavaOpts(cmds));
|
||||
return executeProcess(pb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a process, waits for it to finish and returns the process output.
|
||||
* @param pb The ProcessBuilder to execute.
|
||||
* @return The output from the process.
|
||||
*/
|
||||
public static OutputAnalyzer executeProcess(ProcessBuilder pb) throws Throwable {
|
||||
OutputAnalyzer output = null;
|
||||
try {
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
return output;
|
||||
} catch (Throwable t) {
|
||||
System.out.println("executeProcess() failed: " + t);
|
||||
throw t;
|
||||
} finally {
|
||||
System.out.println(getProcessLog(pb, output));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a process, waits for it to finish and returns the process output.
|
||||
* @param cmds The command line to execute.
|
||||
* @return The output from the process.
|
||||
*/
|
||||
public static OutputAnalyzer executeProcess(String... cmds) throws Throwable {
|
||||
return executeProcess(new ProcessBuilder(cmds));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to log command line, stdout, stderr and exit code from an executed process.
|
||||
* @param pb The executed process.
|
||||
* @param output The output from the process.
|
||||
*/
|
||||
public static String getProcessLog(ProcessBuilder pb, OutputAnalyzer output) {
|
||||
String stderr = output == null ? "null" : output.getStderr();
|
||||
String stdout = output == null ? "null" : output.getStdout();
|
||||
String exitValue = output == null ? "null": Integer.toString(output.getExitValue());
|
||||
StringBuilder logMsg = new StringBuilder();
|
||||
final String nl = System.getProperty("line.separator");
|
||||
logMsg.append("--- ProcessLog ---" + nl);
|
||||
logMsg.append("cmd: " + getCommandLine(pb) + nl);
|
||||
logMsg.append("exitvalue: " + exitValue + nl);
|
||||
logMsg.append("stderr: " + stderr + nl);
|
||||
logMsg.append("stdout: " + stdout + nl);
|
||||
return logMsg.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The full command line for the ProcessBuilder.
|
||||
*/
|
||||
public static String getCommandLine(ProcessBuilder pb) {
|
||||
if (pb == null) {
|
||||
return "null";
|
||||
}
|
||||
StringBuilder cmd = new StringBuilder();
|
||||
for (String s : pb.command()) {
|
||||
cmd.append(s).append(" ");
|
||||
}
|
||||
return cmd.toString().trim();
|
||||
}
|
||||
}
|
||||
|
263
hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java
Normal file
263
hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.oracle.java.testlibrary;
|
||||
|
||||
import static com.oracle.java.testlibrary.Asserts.assertTrue;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
/**
|
||||
* Common library for various test helper functions.
|
||||
*/
|
||||
public final class Utils {
|
||||
|
||||
/**
|
||||
* Returns the sequence used by operating system to separate lines.
|
||||
*/
|
||||
public static final String NEW_LINE = System.getProperty("line.separator");
|
||||
|
||||
/**
|
||||
* Returns the value of 'test.vm.opts'system property.
|
||||
*/
|
||||
public static final String VM_OPTIONS = System.getProperty("test.vm.opts", "").trim();
|
||||
|
||||
/**
|
||||
* Returns the value of 'test.java.opts'system property.
|
||||
*/
|
||||
public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim();
|
||||
|
||||
/**
|
||||
* Returns the value of 'test.timeout.factor' system property
|
||||
* converted to {@code double}.
|
||||
*/
|
||||
public static final double TIMEOUT_FACTOR;
|
||||
static {
|
||||
String toFactor = System.getProperty("test.timeout.factor", "1.0");
|
||||
TIMEOUT_FACTOR = Double.parseDouble(toFactor);
|
||||
}
|
||||
|
||||
private Utils() {
|
||||
// Private constructor to prevent class instantiation
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of VM options.
|
||||
*
|
||||
* @return List of VM options
|
||||
*/
|
||||
public static List<String> getVmOptions() {
|
||||
return Arrays.asList(safeSplitString(VM_OPTIONS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of VM options with -J prefix.
|
||||
*
|
||||
* @return The list of VM options with -J prefix
|
||||
*/
|
||||
public static List<String> getForwardVmOptions() {
|
||||
String[] opts = safeSplitString(VM_OPTIONS);
|
||||
for (int i = 0; i < opts.length; i++) {
|
||||
opts[i] = "-J" + opts[i];
|
||||
}
|
||||
return Arrays.asList(opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default JTReg arguments for a jvm running a test.
|
||||
* This is the combination of JTReg arguments test.vm.opts and test.java.opts.
|
||||
* @return An array of options, or an empty array if no opptions.
|
||||
*/
|
||||
public static String[] getTestJavaOpts() {
|
||||
List<String> opts = new ArrayList<String>();
|
||||
Collections.addAll(opts, safeSplitString(VM_OPTIONS));
|
||||
Collections.addAll(opts, safeSplitString(JAVA_OPTIONS));
|
||||
return opts.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines given arguments with default JTReg arguments for a jvm running a test.
|
||||
* This is the combination of JTReg arguments test.vm.opts and test.java.opts
|
||||
* @return The combination of JTReg test java options and user args.
|
||||
*/
|
||||
public static String[] addTestJavaOpts(String... userArgs) {
|
||||
List<String> opts = new ArrayList<String>();
|
||||
Collections.addAll(opts, getTestJavaOpts());
|
||||
Collections.addAll(opts, userArgs);
|
||||
return opts.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits a string by white space.
|
||||
* Works like String.split(), but returns an empty array
|
||||
* if the string is null or empty.
|
||||
*/
|
||||
private static String[] safeSplitString(String s) {
|
||||
if (s == null || s.trim().isEmpty()) {
|
||||
return new String[] {};
|
||||
}
|
||||
return s.trim().split("\\s+");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The full command line for the ProcessBuilder.
|
||||
*/
|
||||
public static String getCommandLine(ProcessBuilder pb) {
|
||||
StringBuilder cmd = new StringBuilder();
|
||||
for (String s : pb.command()) {
|
||||
cmd.append(s).append(" ");
|
||||
}
|
||||
return cmd.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the free port on the local host.
|
||||
* The function will spin until a valid port number is found.
|
||||
*
|
||||
* @return The port number
|
||||
* @throws InterruptedException if any thread has interrupted the current thread
|
||||
* @throws IOException if an I/O error occurs when opening the socket
|
||||
*/
|
||||
public static int getFreePort() throws InterruptedException, IOException {
|
||||
int port = -1;
|
||||
|
||||
while (port <= 0) {
|
||||
Thread.sleep(100);
|
||||
|
||||
ServerSocket serverSocket = null;
|
||||
try {
|
||||
serverSocket = new ServerSocket(0);
|
||||
port = serverSocket.getLocalPort();
|
||||
} finally {
|
||||
serverSocket.close();
|
||||
}
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the local host.
|
||||
*
|
||||
* @return The host name
|
||||
* @throws UnknownHostException if IP address of a host could not be determined
|
||||
*/
|
||||
public static String getHostname() throws UnknownHostException {
|
||||
InetAddress inetAddress = InetAddress.getLocalHost();
|
||||
String hostName = inetAddress.getHostName();
|
||||
|
||||
assertTrue((hostName != null && !hostName.isEmpty()),
|
||||
"Cannot get hostname");
|
||||
|
||||
return hostName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses "jcmd -l" to search for a jvm pid. This function will wait
|
||||
* forever (until jtreg timeout) for the pid to be found.
|
||||
* @param key Regular expression to search for
|
||||
* @return The found pid.
|
||||
*/
|
||||
public static int waitForJvmPid(String key) throws Throwable {
|
||||
final long iterationSleepMillis = 250;
|
||||
System.out.println("waitForJvmPid: Waiting for key '" + key + "'");
|
||||
System.out.flush();
|
||||
while (true) {
|
||||
int pid = tryFindJvmPid(key);
|
||||
if (pid >= 0) {
|
||||
return pid;
|
||||
}
|
||||
Thread.sleep(iterationSleepMillis);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a jvm pid in the output from "jcmd -l".
|
||||
*
|
||||
* Example output from jcmd is:
|
||||
* 12498 sun.tools.jcmd.JCmd -l
|
||||
* 12254 /tmp/jdk8/tl/jdk/JTwork/classes/com/sun/tools/attach/Application.jar
|
||||
*
|
||||
* @param key A regular expression to search for.
|
||||
* @return The found pid, or -1 if Enot found.
|
||||
* @throws Exception If multiple matching jvms are found.
|
||||
*/
|
||||
public static int tryFindJvmPid(String key) throws Throwable {
|
||||
OutputAnalyzer output = null;
|
||||
try {
|
||||
JDKToolLauncher jcmdLauncher = JDKToolLauncher.create("jcmd");
|
||||
jcmdLauncher.addToolArg("-l");
|
||||
output = ProcessTools.executeProcess(jcmdLauncher.getCommand());
|
||||
output.shouldHaveExitValue(0);
|
||||
|
||||
// Search for a line starting with numbers (pid), follwed by the key.
|
||||
Pattern pattern = Pattern.compile("([0-9]+)\\s.*(" + key + ").*\\r?\\n");
|
||||
Matcher matcher = pattern.matcher(output.getStdout());
|
||||
|
||||
int pid = -1;
|
||||
if (matcher.find()) {
|
||||
pid = Integer.parseInt(matcher.group(1));
|
||||
System.out.println("findJvmPid.pid: " + pid);
|
||||
if (matcher.find()) {
|
||||
throw new Exception("Found multiple JVM pids for key: " + key);
|
||||
}
|
||||
}
|
||||
return pid;
|
||||
} catch (Throwable t) {
|
||||
System.out.println(String.format("Utils.findJvmPid(%s) failed: %s", key, t));
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns file content as a list of strings
|
||||
*
|
||||
* @param file File to operate on
|
||||
* @return List of strings
|
||||
* @throws IOException
|
||||
*/
|
||||
public static List<String> fileAsList(File file) throws IOException {
|
||||
assertTrue(file.exists() && file.isFile(),
|
||||
file.getAbsolutePath() + " does not exist or not a file");
|
||||
List<String> output = new ArrayList<>();
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file.getAbsolutePath()))) {
|
||||
while (reader.ready()) {
|
||||
output.add(reader.readLine().replace(NEW_LINE, ""));
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user