Merge
This commit is contained in:
commit
80025a5e2b
@ -3619,13 +3619,14 @@ bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
|
|||||||
"possibility of dangling Thread pointer");
|
"possibility of dangling Thread pointer");
|
||||||
|
|
||||||
OSThread* osthread = thread->osthread();
|
OSThread* osthread = thread->osthread();
|
||||||
bool interrupted = osthread->interrupted();
|
|
||||||
// There is no synchronization between the setting of the interrupt
|
// There is no synchronization between the setting of the interrupt
|
||||||
// and it being cleared here. It is critical - see 6535709 - that
|
// and it being cleared here. It is critical - see 6535709 - that
|
||||||
// we only clear the interrupt state, and reset the interrupt event,
|
// we only clear the interrupt state, and reset the interrupt event,
|
||||||
// if we are going to report that we were indeed interrupted - else
|
// if we are going to report that we were indeed interrupted - else
|
||||||
// an interrupt can be "lost", leading to spurious wakeups or lost wakeups
|
// 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) {
|
if (interrupted && clear_interrupted) {
|
||||||
osthread->set_interrupted(false);
|
osthread->set_interrupted(false);
|
||||||
ResetEvent(osthread->interrupt_event());
|
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.
|
* 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
|
||||||
@ -273,8 +273,8 @@ class DebugInfoReadStream : public CompressedReadStream {
|
|||||||
}
|
}
|
||||||
Method* read_method() {
|
Method* read_method() {
|
||||||
Method* o = (Method*)(code()->metadata_at(read_int()));
|
Method* o = (Method*)(code()->metadata_at(read_int()));
|
||||||
assert(o == NULL ||
|
// is_metadata() is a faster check than is_metaspace_object()
|
||||||
o->is_metaspace_object(), "meta data only");
|
assert(o == NULL || o->is_metadata(), "meta data only");
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
ScopeValue* read_object_value();
|
ScopeValue* read_object_value();
|
||||||
|
@ -1295,6 +1295,7 @@ void ConstantPool::copy_entry_to(constantPoolHandle from_cp, int from_i,
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_UnresolvedClass:
|
case JVM_CONSTANT_UnresolvedClass:
|
||||||
|
case JVM_CONSTANT_UnresolvedClassInError:
|
||||||
{
|
{
|
||||||
// Can be resolved after checking tag, so check the slot first.
|
// Can be resolved after checking tag, so check the slot first.
|
||||||
CPSlot entry = from_cp->slot_at(from_i);
|
CPSlot entry = from_cp->slot_at(from_i);
|
||||||
|
@ -42,6 +42,7 @@ class Metadata : public MetaspaceObj {
|
|||||||
// Rehashing support for tables containing pointers to this
|
// Rehashing support for tables containing pointers to this
|
||||||
unsigned int new_hash(juint seed) { ShouldNotReachHere(); return 0; }
|
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_klass() const volatile { return false; }
|
||||||
virtual bool is_method() const volatile { return false; }
|
virtual bool is_method() const volatile { return false; }
|
||||||
virtual bool is_methodData() 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);
|
// private native boolean java.lang.Thread.isInterrupted(boolean ClearInterrupted);
|
||||||
bool LibraryCallKit::inline_native_isInterrupted() {
|
bool LibraryCallKit::inline_native_isInterrupted() {
|
||||||
// Add a fast path to t.isInterrupted(clear_int):
|
// 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)
|
// ? TLS._osthread._interrupted : /*slow path:*/ t.isInterrupted(clear_int)
|
||||||
// So, in the common case that the interrupt bit is false,
|
// So, in the common case that the interrupt bit is false,
|
||||||
// we avoid making a call into the VM. Even if the interrupt bit
|
// 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
|
// drop through to next case
|
||||||
set_control( _gvn.transform(new (C) IfTrueNode(iff_bit)));
|
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.
|
// (c) Or, if interrupt bit is set and clear_int is false, use 2nd fast path.
|
||||||
Node* clr_arg = argument(1);
|
Node* clr_arg = argument(1);
|
||||||
Node* cmp_arg = _gvn.transform(new (C) CmpINode(clr_arg, intcon(0)));
|
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
|
// drop through to next case
|
||||||
set_control( _gvn.transform(new (C) IfTrueNode(iff_arg)));
|
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.
|
// (d) Otherwise, go to the slow path.
|
||||||
slow_region->add_req(control());
|
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))
|
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->jvm_version = Abstract_VM_Version::jvm_version();
|
||||||
info->update_version = 0; /* 0 in HotSpot Express VM */
|
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
|
// It's fine to update the thread state here because no JVMTI events
|
||||||
// shall be posted for this PopFrame.
|
// 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();
|
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);
|
java_thread->set_popframe_condition(JavaThread::popframe_pending_bit);
|
||||||
// Set pending step flag for this popframe and it is cleared when next
|
// Set pending step flag for this popframe and it is cleared when next
|
||||||
// step event is posted.
|
// step event is posted.
|
||||||
@ -1505,6 +1517,7 @@ JvmtiEnv::GetFrameLocation(JavaThread* java_thread, jint depth, jmethodID* metho
|
|||||||
// depth - pre-checked as non-negative
|
// depth - pre-checked as non-negative
|
||||||
jvmtiError
|
jvmtiError
|
||||||
JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) {
|
JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) {
|
||||||
|
jvmtiError err = JVMTI_ERROR_NONE;
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
uint32_t debug_bits = 0;
|
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");
|
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;
|
int frame_number = state->count_frames() - depth;
|
||||||
state->env_thread_state(this)->set_frame_pop(frame_number);
|
state->env_thread_state(this)->set_frame_pop(frame_number);
|
||||||
|
} else {
|
||||||
return JVMTI_ERROR_NONE;
|
VM_SetFramePop op(this, state, depth);
|
||||||
|
VMThread::execute(&op);
|
||||||
|
err = op.result();
|
||||||
|
}
|
||||||
|
return err;
|
||||||
} /* end NotifyFramePop */
|
} /* end NotifyFramePop */
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "prims/jvmtiEnvThreadState.hpp"
|
#include "prims/jvmtiEnvThreadState.hpp"
|
||||||
#include "prims/jvmtiEventController.hpp"
|
#include "prims/jvmtiEventController.hpp"
|
||||||
#include "prims/jvmtiThreadState.hpp"
|
#include "prims/jvmtiThreadState.hpp"
|
||||||
|
#include "prims/jvmtiThreadState.inline.hpp"
|
||||||
#include "runtime/fieldDescriptor.hpp"
|
#include "runtime/fieldDescriptor.hpp"
|
||||||
#include "runtime/frame.hpp"
|
#include "runtime/frame.hpp"
|
||||||
#include "runtime/handles.inline.hpp"
|
#include "runtime/handles.inline.hpp"
|
||||||
@ -334,6 +335,60 @@ class JvmtiEnvIterator : public StackObj {
|
|||||||
JvmtiEnv* next(JvmtiEnvBase* env) { return env->next_environment(); }
|
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.
|
// VM operation to get monitor information with stack depth.
|
||||||
class VM_GetOwnedMonitorInfo : public VM_Operation {
|
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() {
|
JvmtiFramePops* JvmtiEnvThreadState::get_frame_pops() {
|
||||||
#ifdef ASSERT
|
assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
|
||||||
uint32_t debug_bits = 0;
|
"frame pop data only accessible from same thread or at safepoint");
|
||||||
#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");
|
|
||||||
|
|
||||||
if (_frame_pops == NULL) {
|
if (_frame_pops == NULL) {
|
||||||
_frame_pops = new JvmtiFramePops();
|
_frame_pops = new JvmtiFramePops();
|
||||||
assert(_frame_pops != NULL, "_frame_pops != NULL");
|
assert(_frame_pops != NULL, "_frame_pops != NULL");
|
||||||
@ -209,44 +205,32 @@ bool JvmtiEnvThreadState::has_frame_pops() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JvmtiEnvThreadState::set_frame_pop(int frame_number) {
|
void JvmtiEnvThreadState::set_frame_pop(int frame_number) {
|
||||||
#ifdef ASSERT
|
assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
|
||||||
uint32_t debug_bits = 0;
|
"frame pop data only accessible from same thread or at safepoint");
|
||||||
#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");
|
|
||||||
JvmtiFramePop fpop(frame_number);
|
JvmtiFramePop fpop(frame_number);
|
||||||
JvmtiEventController::set_frame_pop(this, fpop);
|
JvmtiEventController::set_frame_pop(this, fpop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void JvmtiEnvThreadState::clear_frame_pop(int frame_number) {
|
void JvmtiEnvThreadState::clear_frame_pop(int frame_number) {
|
||||||
#ifdef ASSERT
|
assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
|
||||||
uint32_t debug_bits = 0;
|
"frame pop data only accessible from same thread or at safepoint");
|
||||||
#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");
|
|
||||||
JvmtiFramePop fpop(frame_number);
|
JvmtiFramePop fpop(frame_number);
|
||||||
JvmtiEventController::clear_frame_pop(this, fpop);
|
JvmtiEventController::clear_frame_pop(this, fpop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void JvmtiEnvThreadState::clear_to_frame_pop(int frame_number) {
|
void JvmtiEnvThreadState::clear_to_frame_pop(int frame_number) {
|
||||||
#ifdef ASSERT
|
assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
|
||||||
uint32_t debug_bits = 0;
|
"frame pop data only accessible from same thread or at safepoint");
|
||||||
#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");
|
|
||||||
JvmtiFramePop fpop(frame_number);
|
JvmtiFramePop fpop(frame_number);
|
||||||
JvmtiEventController::clear_to_frame_pop(this, fpop);
|
JvmtiEventController::clear_to_frame_pop(this, fpop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool JvmtiEnvThreadState::is_frame_pop(int cur_frame_number) {
|
bool JvmtiEnvThreadState::is_frame_pop(int cur_frame_number) {
|
||||||
#ifdef ASSERT
|
assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
|
||||||
uint32_t debug_bits = 0;
|
"frame pop data only accessible from same thread or at safepoint");
|
||||||
#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");
|
|
||||||
if (!get_thread()->is_interp_only_mode() || _frame_pops == NULL) {
|
if (!get_thread()->is_interp_only_mode() || _frame_pops == NULL) {
|
||||||
return false;
|
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.
|
* 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
|
||||||
@ -989,21 +989,21 @@ JvmtiEventController::set_extension_event_callback(JvmtiEnvBase *env,
|
|||||||
|
|
||||||
void
|
void
|
||||||
JvmtiEventController::set_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
|
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);
|
JvmtiEventControllerPrivate::set_frame_pop(ets, fpop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
JvmtiEventController::clear_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
|
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);
|
JvmtiEventControllerPrivate::clear_frame_pop(ets, fpop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
JvmtiEventController::clear_to_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
|
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);
|
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.
|
* 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
|
||||||
@ -63,6 +63,7 @@ JvmtiThreadState::JvmtiThreadState(JavaThread* thread)
|
|||||||
_vm_object_alloc_event_collector = NULL;
|
_vm_object_alloc_event_collector = NULL;
|
||||||
_the_class_for_redefinition_verification = NULL;
|
_the_class_for_redefinition_verification = NULL;
|
||||||
_scratch_class_for_redefinition_verification = NULL;
|
_scratch_class_for_redefinition_verification = NULL;
|
||||||
|
_cur_stack_depth = UNKNOWN_STACK_DEPTH;
|
||||||
|
|
||||||
// JVMTI ForceEarlyReturn support
|
// JVMTI ForceEarlyReturn support
|
||||||
_pending_step_for_earlyret = false;
|
_pending_step_for_earlyret = false;
|
||||||
@ -213,12 +214,9 @@ void JvmtiThreadState::leave_interp_only_mode() {
|
|||||||
|
|
||||||
// Helper routine used in several places
|
// Helper routine used in several places
|
||||||
int JvmtiThreadState::count_frames() {
|
int JvmtiThreadState::count_frames() {
|
||||||
#ifdef ASSERT
|
guarantee(SafepointSynchronize::is_at_safepoint() ||
|
||||||
uint32_t debug_bits = 0;
|
(JavaThread *)Thread::current() == get_thread(),
|
||||||
#endif
|
"must be current thread or at safepoint");
|
||||||
assert(SafepointSynchronize::is_at_safepoint() ||
|
|
||||||
JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
|
|
||||||
"at safepoint or must be suspended");
|
|
||||||
|
|
||||||
if (!get_thread()->has_last_Java_frame()) return 0; // no Java frames
|
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() {
|
void JvmtiThreadState::invalidate_cur_stack_depth() {
|
||||||
Thread *cur = Thread::current();
|
guarantee(SafepointSynchronize::is_at_safepoint() ||
|
||||||
uint32_t debug_bits = 0;
|
(JavaThread *)Thread::current() == get_thread(),
|
||||||
|
"must be current thread or at safepoint");
|
||||||
// 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");
|
|
||||||
|
|
||||||
_cur_stack_depth = UNKNOWN_STACK_DEPTH;
|
_cur_stack_depth = UNKNOWN_STACK_DEPTH;
|
||||||
}
|
}
|
||||||
@ -280,10 +272,9 @@ void JvmtiThreadState::decr_cur_stack_depth() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int JvmtiThreadState::cur_stack_depth() {
|
int JvmtiThreadState::cur_stack_depth() {
|
||||||
uint32_t debug_bits = 0;
|
guarantee(SafepointSynchronize::is_at_safepoint() ||
|
||||||
guarantee(JavaThread::current() == get_thread() ||
|
(JavaThread *)Thread::current() == get_thread(),
|
||||||
JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
|
"must be current thread or at safepoint");
|
||||||
"must be current thread or suspended");
|
|
||||||
|
|
||||||
if (!is_interp_only_mode() || _cur_stack_depth == UNKNOWN_STACK_DEPTH) {
|
if (!is_interp_only_mode() || _cur_stack_depth == UNKNOWN_STACK_DEPTH) {
|
||||||
_cur_stack_depth = count_frames();
|
_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.
|
* 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
|
||||||
@ -74,6 +74,8 @@
|
|||||||
template(PopulateDumpSharedSpace) \
|
template(PopulateDumpSharedSpace) \
|
||||||
template(JNIFunctionTableCopier) \
|
template(JNIFunctionTableCopier) \
|
||||||
template(RedefineClasses) \
|
template(RedefineClasses) \
|
||||||
|
template(UpdateForPopTopFrame) \
|
||||||
|
template(SetFramePop) \
|
||||||
template(GetOwnedMonitorInfo) \
|
template(GetOwnedMonitorInfo) \
|
||||||
template(GetObjectMonitorUsage) \
|
template(GetObjectMonitorUsage) \
|
||||||
template(GetCurrentContendedMonitor) \
|
template(GetCurrentContendedMonitor) \
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
* @test
|
* @test
|
||||||
* @bug 6294277
|
* @bug 6294277
|
||||||
* @summary java -Xdebug crashes on SourceDebugExtension attribute larger than 64K
|
* @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.*;
|
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
|
// Reporting
|
||||||
StringBuilder cmdLine = new StringBuilder();
|
StringBuilder cmdLine = new StringBuilder();
|
||||||
for (String cmd : args)
|
for (String cmd : args) {
|
||||||
cmdLine.append(cmd).append(' ');
|
cmdLine.append(cmd).append(' ');
|
||||||
|
}
|
||||||
System.out.println("Command line: [" + cmdLine.toString() + "]");
|
System.out.println("Command line: [" + cmdLine.toString() + "]");
|
||||||
|
|
||||||
return new ProcessBuilder(args.toArray(new String[args.size()]));
|
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