mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-18 01:54:47 +02:00
Merge
This commit is contained in:
commit
3ea0bee55c
24 changed files with 359 additions and 194 deletions
|
@ -62,7 +62,7 @@ class Win32AttachOperation;
|
||||||
class Win32AttachListener: AllStatic {
|
class Win32AttachListener: AllStatic {
|
||||||
private:
|
private:
|
||||||
enum {
|
enum {
|
||||||
preallocate_count = 4 // number of preallocated operations
|
max_enqueued_operations = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
// protects the preallocated list and the operation list
|
// protects the preallocated list and the operation list
|
||||||
|
@ -83,9 +83,12 @@ class Win32AttachListener: AllStatic {
|
||||||
static void set_tail(Win32AttachOperation* tail) { _tail = tail; }
|
static void set_tail(Win32AttachOperation* tail) { _tail = tail; }
|
||||||
|
|
||||||
|
|
||||||
// used to wakeup the listener
|
// A semaphore is used for communication about enqueued operations.
|
||||||
static HANDLE _wakeup;
|
// The maximum count for the semaphore object will be set to "max_enqueued_operations".
|
||||||
static HANDLE wakeup() { return _wakeup; }
|
// The state of a semaphore is signaled when its count is greater than
|
||||||
|
// zero (there are operations enqueued), and nonsignaled when it is zero.
|
||||||
|
static HANDLE _enqueued_ops_semaphore;
|
||||||
|
static HANDLE enqueued_ops_semaphore() { return _enqueued_ops_semaphore; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum {
|
enum {
|
||||||
|
@ -110,7 +113,7 @@ class Win32AttachListener: AllStatic {
|
||||||
|
|
||||||
// statics
|
// statics
|
||||||
HANDLE Win32AttachListener::_mutex;
|
HANDLE Win32AttachListener::_mutex;
|
||||||
HANDLE Win32AttachListener::_wakeup;
|
HANDLE Win32AttachListener::_enqueued_ops_semaphore;
|
||||||
Win32AttachOperation* Win32AttachListener::_avail;
|
Win32AttachOperation* Win32AttachListener::_avail;
|
||||||
Win32AttachOperation* Win32AttachListener::_head;
|
Win32AttachOperation* Win32AttachListener::_head;
|
||||||
Win32AttachOperation* Win32AttachListener::_tail;
|
Win32AttachOperation* Win32AttachListener::_tail;
|
||||||
|
@ -155,20 +158,19 @@ class Win32AttachOperation: public AttachOperation {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// preallocate the required number of operations
|
// Preallocate the maximum number of operations that can be enqueued.
|
||||||
int Win32AttachListener::init() {
|
int Win32AttachListener::init() {
|
||||||
_mutex = (void*)::CreateMutex(NULL, FALSE, NULL);
|
_mutex = (void*)::CreateMutex(NULL, FALSE, NULL);
|
||||||
guarantee(_mutex != (HANDLE)NULL, "mutex creation failed");
|
guarantee(_mutex != (HANDLE)NULL, "mutex creation failed");
|
||||||
|
|
||||||
_wakeup = ::CreateSemaphore(NULL, 0, 1, NULL);
|
_enqueued_ops_semaphore = ::CreateSemaphore(NULL, 0, max_enqueued_operations, NULL);
|
||||||
guarantee(_wakeup != (HANDLE)NULL, "semaphore creation failed");
|
guarantee(_enqueued_ops_semaphore != (HANDLE)NULL, "semaphore creation failed");
|
||||||
|
|
||||||
set_head(NULL);
|
set_head(NULL);
|
||||||
set_tail(NULL);
|
set_tail(NULL);
|
||||||
|
|
||||||
// preallocate a few operations
|
|
||||||
set_available(NULL);
|
set_available(NULL);
|
||||||
for (int i=0; i<preallocate_count; i++) {
|
|
||||||
|
for (int i=0; i<max_enqueued_operations; i++) {
|
||||||
Win32AttachOperation* op = new Win32AttachOperation();
|
Win32AttachOperation* op = new Win32AttachOperation();
|
||||||
op->set_next(available());
|
op->set_next(available());
|
||||||
set_available(op);
|
set_available(op);
|
||||||
|
@ -221,8 +223,12 @@ int Win32AttachListener::enqueue(char* cmd, char* arg0, char* arg1, char* arg2,
|
||||||
op->set_arg(2, arg2);
|
op->set_arg(2, arg2);
|
||||||
op->set_pipe(pipename);
|
op->set_pipe(pipename);
|
||||||
|
|
||||||
// wakeup the thread waiting for operations
|
// Increment number of enqueued operations.
|
||||||
::ReleaseSemaphore(wakeup(), 1, NULL);
|
// Side effect: Semaphore will be signaled and will release
|
||||||
|
// any blocking waiters (i.e. the AttachListener thread).
|
||||||
|
BOOL not_exceeding_semaphore_maximum_count =
|
||||||
|
::ReleaseSemaphore(enqueued_ops_semaphore(), 1, NULL);
|
||||||
|
guarantee(not_exceeding_semaphore_maximum_count, "invariant");
|
||||||
}
|
}
|
||||||
::ReleaseMutex(mutex());
|
::ReleaseMutex(mutex());
|
||||||
|
|
||||||
|
@ -230,10 +236,12 @@ int Win32AttachListener::enqueue(char* cmd, char* arg0, char* arg1, char* arg2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// dequeue the operation from the head of the operation list. If
|
// dequeue the operation from the head of the operation list.
|
||||||
Win32AttachOperation* Win32AttachListener::dequeue() {
|
Win32AttachOperation* Win32AttachListener::dequeue() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
DWORD res = ::WaitForSingleObject(wakeup(), INFINITE);
|
DWORD res = ::WaitForSingleObject(enqueued_ops_semaphore(), INFINITE);
|
||||||
|
// returning from WaitForSingleObject will have decreased
|
||||||
|
// the current count of the semaphore by 1.
|
||||||
guarantee(res == WAIT_OBJECT_0, "wait failed");
|
guarantee(res == WAIT_OBJECT_0, "wait failed");
|
||||||
|
|
||||||
res = ::WaitForSingleObject(mutex(), INFINITE);
|
res = ::WaitForSingleObject(mutex(), INFINITE);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2012, 2015, 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
|
||||||
|
@ -1091,6 +1091,7 @@ static void merge_in_new_methods(InstanceKlass* klass,
|
||||||
}
|
}
|
||||||
// update idnum for new location
|
// update idnum for new location
|
||||||
merged_methods->at(i)->set_method_idnum(i);
|
merged_methods->at(i)->set_method_idnum(i);
|
||||||
|
merged_methods->at(i)->set_orig_method_idnum(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify correct order
|
// Verify correct order
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2015, 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
|
||||||
|
@ -215,6 +215,7 @@ private:
|
||||||
u2 _max_stack; // Maximum number of entries on the expression stack
|
u2 _max_stack; // Maximum number of entries on the expression stack
|
||||||
u2 _max_locals; // Number of local variables used by this method
|
u2 _max_locals; // Number of local variables used by this method
|
||||||
u2 _size_of_parameters; // size of the parameter block (receiver + arguments) in words
|
u2 _size_of_parameters; // size of the parameter block (receiver + arguments) in words
|
||||||
|
u2 _orig_method_idnum; // Original unique identification number for the method
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
ConstMethod(int byte_code_size,
|
ConstMethod(int byte_code_size,
|
||||||
|
@ -473,6 +474,9 @@ public:
|
||||||
u2 method_idnum() const { return _method_idnum; }
|
u2 method_idnum() const { return _method_idnum; }
|
||||||
void set_method_idnum(u2 idnum) { _method_idnum = idnum; }
|
void set_method_idnum(u2 idnum) { _method_idnum = idnum; }
|
||||||
|
|
||||||
|
u2 orig_method_idnum() const { return _orig_method_idnum; }
|
||||||
|
void set_orig_method_idnum(u2 idnum) { _orig_method_idnum = idnum; }
|
||||||
|
|
||||||
// max stack
|
// max stack
|
||||||
int max_stack() const { return _max_stack; }
|
int max_stack() const { return _max_stack; }
|
||||||
void set_max_stack(int size) { _max_stack = size; }
|
void set_max_stack(int size) { _max_stack = size; }
|
||||||
|
|
|
@ -454,7 +454,6 @@ bool ConstantPoolCacheEntry::adjust_method_entry(Method* old_method,
|
||||||
new_method->name()->as_C_string(),
|
new_method->name()->as_C_string(),
|
||||||
new_method->signature()->as_C_string()));
|
new_method->signature()->as_C_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,7 +481,6 @@ bool ConstantPoolCacheEntry::adjust_method_entry(Method* old_method,
|
||||||
new_method->name()->as_C_string(),
|
new_method->name()->as_C_string(),
|
||||||
new_method->signature()->as_C_string()));
|
new_method->signature()->as_C_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,36 +507,33 @@ bool ConstantPoolCacheEntry::check_no_old_or_obsolete_entries() {
|
||||||
(!f1_as_method()->is_old() && !f1_as_method()->is_obsolete())));
|
(!f1_as_method()->is_old() && !f1_as_method()->is_obsolete())));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConstantPoolCacheEntry::is_interesting_method_entry(Klass* k) {
|
Method* ConstantPoolCacheEntry::get_interesting_method_entry(Klass* k) {
|
||||||
if (!is_method_entry()) {
|
if (!is_method_entry()) {
|
||||||
// not a method entry so not interesting by default
|
// not a method entry so not interesting by default
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Method* m = NULL;
|
Method* m = NULL;
|
||||||
if (is_vfinal()) {
|
if (is_vfinal()) {
|
||||||
// virtual and final so _f2 contains method ptr instead of vtable index
|
// virtual and final so _f2 contains method ptr instead of vtable index
|
||||||
m = f2_as_vfinal_method();
|
m = f2_as_vfinal_method();
|
||||||
} else if (is_f1_null()) {
|
} else if (is_f1_null()) {
|
||||||
// NULL _f1 means this is a virtual entry so also not interesting
|
// NULL _f1 means this is a virtual entry so also not interesting
|
||||||
return false;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
if (!(_f1->is_method())) {
|
if (!(_f1->is_method())) {
|
||||||
// _f1 can also contain a Klass* for an interface
|
// _f1 can also contain a Klass* for an interface
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
m = f1_as_method();
|
m = f1_as_method();
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(m != NULL && m->is_method(), "sanity check");
|
assert(m != NULL && m->is_method(), "sanity check");
|
||||||
if (m == NULL || !m->is_method() || (k != NULL && m->method_holder() != k)) {
|
if (m == NULL || !m->is_method() || (k != NULL && m->method_holder() != k)) {
|
||||||
// robustness for above sanity checks or method is not in
|
// robustness for above sanity checks or method is not in
|
||||||
// the interesting class
|
// the interesting class
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the method is in the interesting class so the entry is interesting
|
// the method is in the interesting class so the entry is interesting
|
||||||
return true;
|
return m;
|
||||||
}
|
}
|
||||||
#endif // INCLUDE_JVMTI
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
||||||
|
@ -626,7 +621,7 @@ void ConstantPoolCache::adjust_method_entries(Method** old_methods, Method** new
|
||||||
Klass* old_holder = old_methods[0]->method_holder();
|
Klass* old_holder = old_methods[0]->method_holder();
|
||||||
|
|
||||||
for (int i = 0; i < length(); i++) {
|
for (int i = 0; i < length(); i++) {
|
||||||
if (!entry_at(i)->is_interesting_method_entry(old_holder)) {
|
if (entry_at(i)->get_interesting_method_entry(old_holder) == NULL) {
|
||||||
// skip uninteresting methods
|
// skip uninteresting methods
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -650,10 +645,33 @@ void ConstantPoolCache::adjust_method_entries(Method** old_methods, Method** new
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If any entry of this ConstantPoolCache points to any of
|
||||||
|
// old_methods, replace it with the corresponding new_method.
|
||||||
|
void ConstantPoolCache::adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed) {
|
||||||
|
for (int i = 0; i < length(); i++) {
|
||||||
|
ConstantPoolCacheEntry* entry = entry_at(i);
|
||||||
|
Method* old_method = entry->get_interesting_method_entry(holder);
|
||||||
|
if (old_method == NULL || !old_method->is_old()) {
|
||||||
|
continue; // skip uninteresting entries
|
||||||
|
}
|
||||||
|
if (old_method->is_deleted()) {
|
||||||
|
// clean up entries with deleted methods
|
||||||
|
entry->initialize_entry(entry->constant_pool_index());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum());
|
||||||
|
|
||||||
|
assert(new_method != NULL, "method_with_idnum() should not be NULL");
|
||||||
|
assert(old_method != new_method, "sanity check");
|
||||||
|
|
||||||
|
entry_at(i)->adjust_method_entry(old_method, new_method, trace_name_printed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// the constant pool cache should never contain old or obsolete methods
|
// the constant pool cache should never contain old or obsolete methods
|
||||||
bool ConstantPoolCache::check_no_old_or_obsolete_entries() {
|
bool ConstantPoolCache::check_no_old_or_obsolete_entries() {
|
||||||
for (int i = 1; i < length(); i++) {
|
for (int i = 1; i < length(); i++) {
|
||||||
if (entry_at(i)->is_interesting_method_entry(NULL) &&
|
if (entry_at(i)->get_interesting_method_entry(NULL) != NULL &&
|
||||||
!entry_at(i)->check_no_old_or_obsolete_entries()) {
|
!entry_at(i)->check_no_old_or_obsolete_entries()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -663,7 +681,7 @@ bool ConstantPoolCache::check_no_old_or_obsolete_entries() {
|
||||||
|
|
||||||
void ConstantPoolCache::dump_cache() {
|
void ConstantPoolCache::dump_cache() {
|
||||||
for (int i = 1; i < length(); i++) {
|
for (int i = 1; i < length(); i++) {
|
||||||
if (entry_at(i)->is_interesting_method_entry(NULL)) {
|
if (entry_at(i)->get_interesting_method_entry(NULL) != NULL) {
|
||||||
entry_at(i)->print(tty, i);
|
entry_at(i)->print(tty, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1998, 2015, 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
|
||||||
|
@ -379,9 +379,9 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
|
||||||
// printed the klass name so that other routines in the adjust_*
|
// printed the klass name so that other routines in the adjust_*
|
||||||
// group don't print the klass name.
|
// group don't print the klass name.
|
||||||
bool adjust_method_entry(Method* old_method, Method* new_method,
|
bool adjust_method_entry(Method* old_method, Method* new_method,
|
||||||
bool * trace_name_printed);
|
bool* trace_name_printed);
|
||||||
bool check_no_old_or_obsolete_entries();
|
bool check_no_old_or_obsolete_entries();
|
||||||
bool is_interesting_method_entry(Klass* k);
|
Method* get_interesting_method_entry(Klass* k);
|
||||||
#endif // INCLUDE_JVMTI
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
||||||
// Debugging & Printing
|
// Debugging & Printing
|
||||||
|
@ -478,7 +478,8 @@ class ConstantPoolCache: public MetaspaceObj {
|
||||||
// printed the klass name so that other routines in the adjust_*
|
// printed the klass name so that other routines in the adjust_*
|
||||||
// group don't print the klass name.
|
// group don't print the klass name.
|
||||||
void adjust_method_entries(Method** old_methods, Method** new_methods,
|
void adjust_method_entries(Method** old_methods, Method** new_methods,
|
||||||
int methods_length, bool * trace_name_printed);
|
int methods_length, bool* trace_name_printed);
|
||||||
|
void adjust_method_entries(InstanceKlass* holder, bool* trace_name_printed);
|
||||||
bool check_no_old_or_obsolete_entries();
|
bool check_no_old_or_obsolete_entries();
|
||||||
void dump_cache();
|
void dump_cache();
|
||||||
#endif // INCLUDE_JVMTI
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
|
@ -2793,16 +2793,21 @@ Method* InstanceKlass::method_at_itable(Klass* holder, int index, TRAPS) {
|
||||||
// not yet in the vtable due to concurrent subclass define and superinterface
|
// not yet in the vtable due to concurrent subclass define and superinterface
|
||||||
// redefinition
|
// redefinition
|
||||||
// Note: those in the vtable, should have been updated via adjust_method_entries
|
// Note: those in the vtable, should have been updated via adjust_method_entries
|
||||||
void InstanceKlass::adjust_default_methods(Method** old_methods, Method** new_methods,
|
void InstanceKlass::adjust_default_methods(InstanceKlass* holder, bool* trace_name_printed) {
|
||||||
int methods_length, bool* trace_name_printed) {
|
|
||||||
// search the default_methods for uses of either obsolete or EMCP methods
|
// search the default_methods for uses of either obsolete or EMCP methods
|
||||||
if (default_methods() != NULL) {
|
if (default_methods() != NULL) {
|
||||||
for (int j = 0; j < methods_length; j++) {
|
|
||||||
Method* old_method = old_methods[j];
|
|
||||||
Method* new_method = new_methods[j];
|
|
||||||
|
|
||||||
for (int index = 0; index < default_methods()->length(); index ++) {
|
for (int index = 0; index < default_methods()->length(); index ++) {
|
||||||
if (default_methods()->at(index) == old_method) {
|
Method* old_method = default_methods()->at(index);
|
||||||
|
if (old_method == NULL || old_method->method_holder() != holder || !old_method->is_old()) {
|
||||||
|
continue; // skip uninteresting entries
|
||||||
|
}
|
||||||
|
assert(!old_method->is_deleted(), "default methods may not be deleted");
|
||||||
|
|
||||||
|
Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum());
|
||||||
|
|
||||||
|
assert(new_method != NULL, "method_with_idnum() should not be NULL");
|
||||||
|
assert(old_method != new_method, "sanity check");
|
||||||
|
|
||||||
default_methods()->at_put(index, new_method);
|
default_methods()->at_put(index, new_method);
|
||||||
if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) {
|
if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) {
|
||||||
if (!(*trace_name_printed)) {
|
if (!(*trace_name_printed)) {
|
||||||
|
@ -2818,8 +2823,6 @@ void InstanceKlass::adjust_default_methods(Method** old_methods, Method** new_me
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif // INCLUDE_JVMTI
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
||||||
|
|
|
@ -937,8 +937,7 @@ class InstanceKlass: public Klass {
|
||||||
Method* method_at_itable(Klass* holder, int index, TRAPS);
|
Method* method_at_itable(Klass* holder, int index, TRAPS);
|
||||||
|
|
||||||
#if INCLUDE_JVMTI
|
#if INCLUDE_JVMTI
|
||||||
void adjust_default_methods(Method** old_methods, Method** new_methods,
|
void adjust_default_methods(InstanceKlass* holder, bool* trace_name_printed);
|
||||||
int methods_length, bool* trace_name_printed);
|
|
||||||
#endif // INCLUDE_JVMTI
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
||||||
// Garbage collection
|
// Garbage collection
|
||||||
|
|
|
@ -863,20 +863,22 @@ bool klassVtable::adjust_default_method(int vtable_index, Method* old_method, Me
|
||||||
}
|
}
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
void klassVtable::adjust_method_entries(Method** old_methods, Method** new_methods,
|
|
||||||
int methods_length, bool * trace_name_printed) {
|
|
||||||
// search the vtable for uses of either obsolete or EMCP methods
|
|
||||||
for (int j = 0; j < methods_length; j++) {
|
|
||||||
Method* old_method = old_methods[j];
|
|
||||||
Method* new_method = new_methods[j];
|
|
||||||
|
|
||||||
// In the vast majority of cases we could get the vtable index
|
// search the vtable for uses of either obsolete or EMCP methods
|
||||||
// by using: old_method->vtable_index()
|
void klassVtable::adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed) {
|
||||||
// However, there are rare cases, eg. sun.awt.X11.XDecoratedPeer.getX()
|
int prn_enabled = 0;
|
||||||
// in sun.awt.X11.XFramePeer where methods occur more than once in the
|
|
||||||
// vtable, so, alas, we must do an exhaustive search.
|
|
||||||
for (int index = 0; index < length(); index++) {
|
for (int index = 0; index < length(); index++) {
|
||||||
if (unchecked_method_at(index) == old_method) {
|
Method* old_method = unchecked_method_at(index);
|
||||||
|
if (old_method == NULL || old_method->method_holder() != holder || !old_method->is_old()) {
|
||||||
|
continue; // skip uninteresting entries
|
||||||
|
}
|
||||||
|
assert(!old_method->is_deleted(), "vtable methods may not be deleted");
|
||||||
|
|
||||||
|
Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum());
|
||||||
|
|
||||||
|
assert(new_method != NULL, "method_with_idnum() should not be NULL");
|
||||||
|
assert(old_method != new_method, "sanity check");
|
||||||
|
|
||||||
put_method_at(new_method, index);
|
put_method_at(new_method, index);
|
||||||
// For default methods, need to update the _default_methods array
|
// For default methods, need to update the _default_methods array
|
||||||
// which can only have one method entry for a given signature
|
// which can only have one method entry for a given signature
|
||||||
|
@ -899,9 +901,6 @@ void klassVtable::adjust_method_entries(Method** old_methods, Method** new_metho
|
||||||
new_method->signature()->as_C_string(),
|
new_method->signature()->as_C_string(),
|
||||||
updated_default ? "true" : "false"));
|
updated_default ? "true" : "false"));
|
||||||
}
|
}
|
||||||
// cannot 'break' here; see for-loop comment above.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1193,20 +1192,22 @@ void klassItable::initialize_with_method(Method* m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#if INCLUDE_JVMTI
|
#if INCLUDE_JVMTI
|
||||||
void klassItable::adjust_method_entries(Method** old_methods, Method** new_methods,
|
// search the itable for uses of either obsolete or EMCP methods
|
||||||
int methods_length, bool * trace_name_printed) {
|
void klassItable::adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed) {
|
||||||
// search the itable for uses of either obsolete or EMCP methods
|
|
||||||
for (int j = 0; j < methods_length; j++) {
|
itableMethodEntry* ime = method_entry(0);
|
||||||
Method* old_method = old_methods[j];
|
for (int i = 0; i < _size_method_table; i++, ime++) {
|
||||||
Method* new_method = new_methods[j];
|
Method* old_method = ime->method();
|
||||||
itableMethodEntry* ime = method_entry(0);
|
if (old_method == NULL || old_method->method_holder() != holder || !old_method->is_old()) {
|
||||||
|
continue; // skip uninteresting entries
|
||||||
|
}
|
||||||
|
assert(!old_method->is_deleted(), "itable methods may not be deleted");
|
||||||
|
|
||||||
|
Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum());
|
||||||
|
|
||||||
|
assert(new_method != NULL, "method_with_idnum() should not be NULL");
|
||||||
|
assert(old_method != new_method, "sanity check");
|
||||||
|
|
||||||
// The itable can describe more than one interface and the same
|
|
||||||
// method signature can be specified by more than one interface.
|
|
||||||
// This means we have to do an exhaustive search to find all the
|
|
||||||
// old_method references.
|
|
||||||
for (int i = 0; i < _size_method_table; i++) {
|
|
||||||
if (ime->method() == old_method) {
|
|
||||||
ime->initialize(new_method);
|
ime->initialize(new_method);
|
||||||
|
|
||||||
if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) {
|
if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) {
|
||||||
|
@ -1221,10 +1222,6 @@ void klassItable::adjust_method_entries(Method** old_methods, Method** new_metho
|
||||||
new_method->name()->as_C_string(),
|
new_method->name()->as_C_string(),
|
||||||
new_method->signature()->as_C_string()));
|
new_method->signature()->as_C_string()));
|
||||||
}
|
}
|
||||||
// cannot 'break' here; see for-loop comment above.
|
|
||||||
}
|
|
||||||
ime++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2015, 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
|
||||||
|
@ -98,8 +98,7 @@ class klassVtable : public ResourceObj {
|
||||||
// printed the klass name so that other routines in the adjust_*
|
// printed the klass name so that other routines in the adjust_*
|
||||||
// group don't print the klass name.
|
// group don't print the klass name.
|
||||||
bool adjust_default_method(int vtable_index, Method* old_method, Method* new_method);
|
bool adjust_default_method(int vtable_index, Method* old_method, Method* new_method);
|
||||||
void adjust_method_entries(Method** old_methods, Method** new_methods,
|
void adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed);
|
||||||
int methods_length, bool * trace_name_printed);
|
|
||||||
bool check_no_old_or_obsolete_entries();
|
bool check_no_old_or_obsolete_entries();
|
||||||
void dump_vtable();
|
void dump_vtable();
|
||||||
#endif // INCLUDE_JVMTI
|
#endif // INCLUDE_JVMTI
|
||||||
|
@ -288,8 +287,7 @@ class klassItable : public ResourceObj {
|
||||||
// trace_name_printed is set to true if the current call has
|
// trace_name_printed is set to true if the current call has
|
||||||
// printed the klass name so that other routines in the adjust_*
|
// printed the klass name so that other routines in the adjust_*
|
||||||
// group don't print the klass name.
|
// group don't print the klass name.
|
||||||
void adjust_method_entries(Method** old_methods, Method** new_methods,
|
void adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed);
|
||||||
int methods_length, bool * trace_name_printed);
|
|
||||||
bool check_no_old_or_obsolete_entries();
|
bool check_no_old_or_obsolete_entries();
|
||||||
void dump_itable();
|
void dump_itable();
|
||||||
#endif // INCLUDE_JVMTI
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
|
@ -1450,6 +1450,7 @@ void Method::sort_methods(Array<Method*>* methods, bool idempotent, bool set_idn
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
Method* m = methods->at(i);
|
Method* m = methods->at(i);
|
||||||
m->set_method_idnum(i);
|
m->set_method_idnum(i);
|
||||||
|
m->set_orig_method_idnum(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2015, 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
|
||||||
|
@ -233,6 +233,9 @@ class Method : public Metadata {
|
||||||
u2 method_idnum() const { return constMethod()->method_idnum(); }
|
u2 method_idnum() const { return constMethod()->method_idnum(); }
|
||||||
void set_method_idnum(u2 idnum) { constMethod()->set_method_idnum(idnum); }
|
void set_method_idnum(u2 idnum) { constMethod()->set_method_idnum(idnum); }
|
||||||
|
|
||||||
|
u2 orig_method_idnum() const { return constMethod()->orig_method_idnum(); }
|
||||||
|
void set_orig_method_idnum(u2 idnum) { constMethod()->set_orig_method_idnum(idnum); }
|
||||||
|
|
||||||
// code size
|
// code size
|
||||||
int code_size() const { return constMethod()->code_size(); }
|
int code_size() const { return constMethod()->code_size(); }
|
||||||
|
|
||||||
|
|
|
@ -782,9 +782,13 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions(
|
||||||
Method* idnum_owner = scratch_class->method_with_idnum(old_num);
|
Method* idnum_owner = scratch_class->method_with_idnum(old_num);
|
||||||
if (idnum_owner != NULL) {
|
if (idnum_owner != NULL) {
|
||||||
// There is already a method assigned this idnum -- switch them
|
// There is already a method assigned this idnum -- switch them
|
||||||
|
// Take current and original idnum from the new_method
|
||||||
idnum_owner->set_method_idnum(new_num);
|
idnum_owner->set_method_idnum(new_num);
|
||||||
|
idnum_owner->set_orig_method_idnum(k_new_method->orig_method_idnum());
|
||||||
}
|
}
|
||||||
|
// Take current and original idnum from the old_method
|
||||||
k_new_method->set_method_idnum(old_num);
|
k_new_method->set_method_idnum(old_num);
|
||||||
|
k_new_method->set_orig_method_idnum(k_old_method->orig_method_idnum());
|
||||||
if (thread->has_pending_exception()) {
|
if (thread->has_pending_exception()) {
|
||||||
return JVMTI_ERROR_OUT_OF_MEMORY;
|
return JVMTI_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
@ -817,9 +821,12 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions(
|
||||||
Method* idnum_owner = scratch_class->method_with_idnum(num);
|
Method* idnum_owner = scratch_class->method_with_idnum(num);
|
||||||
if (idnum_owner != NULL) {
|
if (idnum_owner != NULL) {
|
||||||
// There is already a method assigned this idnum -- switch them
|
// There is already a method assigned this idnum -- switch them
|
||||||
|
// Take current and original idnum from the new_method
|
||||||
idnum_owner->set_method_idnum(new_num);
|
idnum_owner->set_method_idnum(new_num);
|
||||||
|
idnum_owner->set_orig_method_idnum(k_new_method->orig_method_idnum());
|
||||||
}
|
}
|
||||||
k_new_method->set_method_idnum(num);
|
k_new_method->set_method_idnum(num);
|
||||||
|
k_new_method->set_orig_method_idnum(num);
|
||||||
if (thread->has_pending_exception()) {
|
if (thread->has_pending_exception()) {
|
||||||
return JVMTI_ERROR_OUT_OF_MEMORY;
|
return JVMTI_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
@ -3327,6 +3334,7 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) {
|
||||||
// This is a very busy routine. We don't want too much tracing
|
// This is a very busy routine. We don't want too much tracing
|
||||||
// printed out.
|
// printed out.
|
||||||
bool trace_name_printed = false;
|
bool trace_name_printed = false;
|
||||||
|
InstanceKlass *the_class = InstanceKlass::cast(_the_class_oop);
|
||||||
|
|
||||||
// Very noisy: only enable this call if you are trying to determine
|
// Very noisy: only enable this call if you are trying to determine
|
||||||
// that a specific class gets found by this routine.
|
// that a specific class gets found by this routine.
|
||||||
|
@ -3338,10 +3346,8 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) {
|
||||||
// If the class being redefined is java.lang.Object, we need to fix all
|
// If the class being redefined is java.lang.Object, we need to fix all
|
||||||
// array class vtables also
|
// array class vtables also
|
||||||
if (k->oop_is_array() && _the_class_oop == SystemDictionary::Object_klass()) {
|
if (k->oop_is_array() && _the_class_oop == SystemDictionary::Object_klass()) {
|
||||||
k->vtable()->adjust_method_entries(_matching_old_methods,
|
k->vtable()->adjust_method_entries(the_class, &trace_name_printed);
|
||||||
_matching_new_methods,
|
|
||||||
_matching_methods_length,
|
|
||||||
&trace_name_printed);
|
|
||||||
} else if (k->oop_is_instance()) {
|
} else if (k->oop_is_instance()) {
|
||||||
HandleMark hm(_thread);
|
HandleMark hm(_thread);
|
||||||
InstanceKlass *ik = InstanceKlass::cast(k);
|
InstanceKlass *ik = InstanceKlass::cast(k);
|
||||||
|
@ -3383,14 +3389,9 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) {
|
||||||
|| ik->is_subtype_of(_the_class_oop))) {
|
|| ik->is_subtype_of(_the_class_oop))) {
|
||||||
// ik->vtable() creates a wrapper object; rm cleans it up
|
// ik->vtable() creates a wrapper object; rm cleans it up
|
||||||
ResourceMark rm(_thread);
|
ResourceMark rm(_thread);
|
||||||
ik->vtable()->adjust_method_entries(_matching_old_methods,
|
|
||||||
_matching_new_methods,
|
ik->vtable()->adjust_method_entries(the_class, &trace_name_printed);
|
||||||
_matching_methods_length,
|
ik->adjust_default_methods(the_class, &trace_name_printed);
|
||||||
&trace_name_printed);
|
|
||||||
ik->adjust_default_methods(_matching_old_methods,
|
|
||||||
_matching_new_methods,
|
|
||||||
_matching_methods_length,
|
|
||||||
&trace_name_printed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the current class has an itable and we are either redefining an
|
// If the current class has an itable and we are either redefining an
|
||||||
|
@ -3405,10 +3406,8 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) {
|
||||||
|| ik->is_subclass_of(_the_class_oop))) {
|
|| ik->is_subclass_of(_the_class_oop))) {
|
||||||
// ik->itable() creates a wrapper object; rm cleans it up
|
// ik->itable() creates a wrapper object; rm cleans it up
|
||||||
ResourceMark rm(_thread);
|
ResourceMark rm(_thread);
|
||||||
ik->itable()->adjust_method_entries(_matching_old_methods,
|
|
||||||
_matching_new_methods,
|
ik->itable()->adjust_method_entries(the_class, &trace_name_printed);
|
||||||
_matching_methods_length,
|
|
||||||
&trace_name_printed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The constant pools in other classes (other_cp) can refer to
|
// The constant pools in other classes (other_cp) can refer to
|
||||||
|
@ -3432,10 +3431,7 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) {
|
||||||
other_cp = constantPoolHandle(ik->constants());
|
other_cp = constantPoolHandle(ik->constants());
|
||||||
cp_cache = other_cp->cache();
|
cp_cache = other_cp->cache();
|
||||||
if (cp_cache != NULL) {
|
if (cp_cache != NULL) {
|
||||||
cp_cache->adjust_method_entries(_matching_old_methods,
|
cp_cache->adjust_method_entries(the_class, &trace_name_printed);
|
||||||
_matching_new_methods,
|
|
||||||
_matching_methods_length,
|
|
||||||
&trace_name_printed);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3578,6 +3574,7 @@ int VM_RedefineClasses::check_methods_and_mark_as_obsolete() {
|
||||||
|
|
||||||
// obsolete methods need a unique idnum so they become new entries in
|
// obsolete methods need a unique idnum so they become new entries in
|
||||||
// the jmethodID cache in InstanceKlass
|
// the jmethodID cache in InstanceKlass
|
||||||
|
assert(old_method->method_idnum() == new_method->method_idnum(), "must match");
|
||||||
u2 num = InstanceKlass::cast(_the_class_oop)->next_method_idnum();
|
u2 num = InstanceKlass::cast(_the_class_oop)->next_method_idnum();
|
||||||
if (num != ConstMethod::UNSET_IDNUM) {
|
if (num != ConstMethod::UNSET_IDNUM) {
|
||||||
old_method->set_method_idnum(num);
|
old_method->set_method_idnum(num);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2015, 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
|
||||||
|
@ -421,9 +421,11 @@ void before_exit(JavaThread * thread) {
|
||||||
os::infinite_sleep();
|
os::infinite_sleep();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Terminate watcher thread - must before disenrolling any periodic task
|
// Stop the WatcherThread. We do this before disenrolling various
|
||||||
if (PeriodicTask::num_tasks() > 0)
|
// PeriodicTasks to reduce the likelihood of races.
|
||||||
|
if (PeriodicTask::num_tasks() > 0) {
|
||||||
WatcherThread::stop();
|
WatcherThread::stop();
|
||||||
|
}
|
||||||
|
|
||||||
// Print statistics gathered (profiling ...)
|
// Print statistics gathered (profiling ...)
|
||||||
if (Arguments::has_profile()) {
|
if (Arguments::has_profile()) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2015, 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
|
||||||
|
@ -47,6 +47,8 @@ void PeriodicTask::print_intervals() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void PeriodicTask::real_time_tick(int delay_time) {
|
void PeriodicTask::real_time_tick(int delay_time) {
|
||||||
|
assert(Thread::current()->is_Watcher_thread(), "must be WatcherThread");
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (ProfilerCheckIntervals) {
|
if (ProfilerCheckIntervals) {
|
||||||
_ticks++;
|
_ticks++;
|
||||||
|
@ -60,6 +62,8 @@ void PeriodicTask::real_time_tick(int delay_time) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
|
// The WatcherThread does not participate in the safepoint protocol
|
||||||
|
// for the PeriodicTask_lock because it is not a JavaThread.
|
||||||
MutexLockerEx ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
MutexLockerEx ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
||||||
int orig_num_tasks = _num_tasks;
|
int orig_num_tasks = _num_tasks;
|
||||||
|
|
||||||
|
@ -74,8 +78,7 @@ void PeriodicTask::real_time_tick(int delay_time) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int PeriodicTask::time_to_wait() {
|
int PeriodicTask::time_to_wait() {
|
||||||
MutexLockerEx ml(PeriodicTask_lock->owned_by_self() ?
|
assert(PeriodicTask_lock->owned_by_self(), "PeriodicTask_lock required");
|
||||||
NULL : PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
|
||||||
|
|
||||||
if (_num_tasks == 0) {
|
if (_num_tasks == 0) {
|
||||||
return 0; // sleep until shutdown or a task is enrolled
|
return 0; // sleep until shutdown or a task is enrolled
|
||||||
|
@ -98,14 +101,19 @@ PeriodicTask::PeriodicTask(size_t interval_time) :
|
||||||
}
|
}
|
||||||
|
|
||||||
PeriodicTask::~PeriodicTask() {
|
PeriodicTask::~PeriodicTask() {
|
||||||
|
// This PeriodicTask may have already been disenrolled by a call
|
||||||
|
// to disenroll() before the PeriodicTask was deleted.
|
||||||
disenroll();
|
disenroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* enroll could be called from a JavaThread, so we have to check for
|
// enroll the current PeriodicTask
|
||||||
* safepoint when taking the lock to avoid deadlocking */
|
|
||||||
void PeriodicTask::enroll() {
|
void PeriodicTask::enroll() {
|
||||||
MutexLockerEx ml(PeriodicTask_lock->owned_by_self() ?
|
// Follow normal safepoint aware lock enter protocol if the caller does
|
||||||
NULL : PeriodicTask_lock);
|
// not already own the PeriodicTask_lock. Otherwise, we don't try to
|
||||||
|
// enter it again because VM internal Mutexes do not support recursion.
|
||||||
|
//
|
||||||
|
MutexLockerEx ml(PeriodicTask_lock->owned_by_self() ? NULL
|
||||||
|
: PeriodicTask_lock);
|
||||||
|
|
||||||
if (_num_tasks == PeriodicTask::max_tasks) {
|
if (_num_tasks == PeriodicTask::max_tasks) {
|
||||||
fatal("Overflow in PeriodicTask table");
|
fatal("Overflow in PeriodicTask table");
|
||||||
|
@ -113,18 +121,21 @@ void PeriodicTask::enroll() {
|
||||||
_tasks[_num_tasks++] = this;
|
_tasks[_num_tasks++] = this;
|
||||||
|
|
||||||
WatcherThread* thread = WatcherThread::watcher_thread();
|
WatcherThread* thread = WatcherThread::watcher_thread();
|
||||||
if (thread) {
|
if (thread != NULL) {
|
||||||
thread->unpark();
|
thread->unpark();
|
||||||
} else {
|
} else {
|
||||||
WatcherThread::start();
|
WatcherThread::start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* disenroll could be called from a JavaThread, so we have to check for
|
// disenroll the current PeriodicTask
|
||||||
* safepoint when taking the lock to avoid deadlocking */
|
|
||||||
void PeriodicTask::disenroll() {
|
void PeriodicTask::disenroll() {
|
||||||
MutexLockerEx ml(PeriodicTask_lock->owned_by_self() ?
|
// Follow normal safepoint aware lock enter protocol if the caller does
|
||||||
NULL : PeriodicTask_lock);
|
// not already own the PeriodicTask_lock. Otherwise, we don't try to
|
||||||
|
// enter it again because VM internal Mutexes do not support recursion.
|
||||||
|
//
|
||||||
|
MutexLockerEx ml(PeriodicTask_lock->owned_by_self() ? NULL
|
||||||
|
: PeriodicTask_lock);
|
||||||
|
|
||||||
int index;
|
int index;
|
||||||
for(index = 0; index < _num_tasks && _tasks[index] != this; index++)
|
for(index = 0; index < _num_tasks && _tasks[index] != this; index++)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2015, 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
|
||||||
|
@ -54,6 +54,7 @@ class PeriodicTask: public CHeapObj<mtInternal> {
|
||||||
|
|
||||||
static int _num_tasks;
|
static int _num_tasks;
|
||||||
static PeriodicTask* _tasks[PeriodicTask::max_tasks];
|
static PeriodicTask* _tasks[PeriodicTask::max_tasks];
|
||||||
|
// Can only be called by the WatcherThread
|
||||||
static void real_time_tick(int delay_time);
|
static void real_time_tick(int delay_time);
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
|
@ -98,6 +99,7 @@ class PeriodicTask: public CHeapObj<mtInternal> {
|
||||||
|
|
||||||
// Calculate when the next periodic task will fire.
|
// Calculate when the next periodic task will fire.
|
||||||
// Called by the WatcherThread's run method.
|
// Called by the WatcherThread's run method.
|
||||||
|
// Requires the PeriodicTask_lock.
|
||||||
static int time_to_wait();
|
static int time_to_wait();
|
||||||
|
|
||||||
// The task to perform at each period
|
// The task to perform at each period
|
||||||
|
|
|
@ -1201,8 +1201,15 @@ WatcherThread::WatcherThread() : Thread(), _crash_protection(NULL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int WatcherThread::sleep() const {
|
int WatcherThread::sleep() const {
|
||||||
|
// The WatcherThread does not participate in the safepoint protocol
|
||||||
|
// for the PeriodicTask_lock because it is not a JavaThread.
|
||||||
MutexLockerEx ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
MutexLockerEx ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
||||||
|
|
||||||
|
if (_should_terminate) {
|
||||||
|
// check for termination before we do any housekeeping or wait
|
||||||
|
return 0; // we did not sleep.
|
||||||
|
}
|
||||||
|
|
||||||
// remaining will be zero if there are no tasks,
|
// remaining will be zero if there are no tasks,
|
||||||
// causing the WatcherThread to sleep until a task is
|
// causing the WatcherThread to sleep until a task is
|
||||||
// enrolled
|
// enrolled
|
||||||
|
@ -1215,8 +1222,9 @@ int WatcherThread::sleep() const {
|
||||||
|
|
||||||
jlong time_before_loop = os::javaTimeNanos();
|
jlong time_before_loop = os::javaTimeNanos();
|
||||||
|
|
||||||
for (;;) {
|
while (true) {
|
||||||
bool timedout = PeriodicTask_lock->wait(Mutex::_no_safepoint_check_flag, remaining);
|
bool timedout = PeriodicTask_lock->wait(Mutex::_no_safepoint_check_flag,
|
||||||
|
remaining);
|
||||||
jlong now = os::javaTimeNanos();
|
jlong now = os::javaTimeNanos();
|
||||||
|
|
||||||
if (remaining == 0) {
|
if (remaining == 0) {
|
||||||
|
@ -1257,7 +1265,7 @@ void WatcherThread::run() {
|
||||||
this->initialize_thread_local_storage();
|
this->initialize_thread_local_storage();
|
||||||
this->set_native_thread_name(this->name());
|
this->set_native_thread_name(this->name());
|
||||||
this->set_active_handles(JNIHandleBlock::allocate_block());
|
this->set_active_handles(JNIHandleBlock::allocate_block());
|
||||||
while (!_should_terminate) {
|
while (true) {
|
||||||
assert(watcher_thread() == Thread::current(), "thread consistency check");
|
assert(watcher_thread() == Thread::current(), "thread consistency check");
|
||||||
assert(watcher_thread() == this, "thread consistency check");
|
assert(watcher_thread() == this, "thread consistency check");
|
||||||
|
|
||||||
|
@ -1293,6 +1301,11 @@ void WatcherThread::run() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_should_terminate) {
|
||||||
|
// check for termination before posting the next tick
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
PeriodicTask::real_time_tick(time_waited);
|
PeriodicTask::real_time_tick(time_waited);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1323,27 +1336,19 @@ void WatcherThread::make_startable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatcherThread::stop() {
|
void WatcherThread::stop() {
|
||||||
// Get the PeriodicTask_lock if we can. If we cannot, then the
|
{
|
||||||
// WatcherThread is using it and we don't want to block on that lock
|
// Follow normal safepoint aware lock enter protocol since the
|
||||||
// here because that might cause a safepoint deadlock depending on
|
// WatcherThread is stopped by another JavaThread.
|
||||||
// what the current WatcherThread tasks are doing.
|
MutexLocker ml(PeriodicTask_lock);
|
||||||
bool have_lock = PeriodicTask_lock->try_lock();
|
|
||||||
|
|
||||||
_should_terminate = true;
|
_should_terminate = true;
|
||||||
OrderAccess::fence(); // ensure WatcherThread sees update in main loop
|
|
||||||
|
|
||||||
if (have_lock) {
|
|
||||||
WatcherThread* watcher = watcher_thread();
|
WatcherThread* watcher = watcher_thread();
|
||||||
if (watcher != NULL) {
|
if (watcher != NULL) {
|
||||||
// If we managed to get the lock, then we should unpark the
|
// unpark the WatcherThread so it can see that it should terminate
|
||||||
// WatcherThread so that it can see we want it to stop.
|
|
||||||
watcher->unpark();
|
watcher->unpark();
|
||||||
}
|
}
|
||||||
|
|
||||||
PeriodicTask_lock->unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// it is ok to take late safepoints here, if needed
|
|
||||||
MutexLocker mu(Terminator_lock);
|
MutexLocker mu(Terminator_lock);
|
||||||
|
|
||||||
while (watcher_thread() != NULL) {
|
while (watcher_thread() != NULL) {
|
||||||
|
@ -1363,9 +1368,7 @@ void WatcherThread::stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatcherThread::unpark() {
|
void WatcherThread::unpark() {
|
||||||
MutexLockerEx ml(PeriodicTask_lock->owned_by_self()
|
assert(PeriodicTask_lock->owned_by_self(), "PeriodicTask_lock required");
|
||||||
? NULL
|
|
||||||
: PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
|
||||||
PeriodicTask_lock->notify();
|
PeriodicTask_lock->notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3562,8 +3565,8 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
MutexLockerEx ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
MutexLocker ml(PeriodicTask_lock);
|
||||||
// Make sure the watcher thread can be started by WatcherThread::start()
|
// Make sure the WatcherThread can be started by WatcherThread::start()
|
||||||
// or by dynamic enrollment.
|
// or by dynamic enrollment.
|
||||||
WatcherThread::make_startable();
|
WatcherThread::make_startable();
|
||||||
// Start up the WatcherThread if there are any periodic tasks
|
// Start up the WatcherThread if there are any periodic tasks
|
||||||
|
|
|
@ -702,7 +702,8 @@ class WatcherThread: public Thread {
|
||||||
static WatcherThread* _watcher_thread;
|
static WatcherThread* _watcher_thread;
|
||||||
|
|
||||||
static bool _startable;
|
static bool _startable;
|
||||||
volatile static bool _should_terminate; // updated without holding lock
|
// volatile due to at least one lock-free read
|
||||||
|
volatile static bool _should_terminate;
|
||||||
|
|
||||||
os::WatcherThreadCrashProtection* _crash_protection;
|
os::WatcherThreadCrashProtection* _crash_protection;
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -47,6 +47,7 @@ public class AssertSafepointCheckConsistency1 {
|
||||||
"-XX:+UnlockDiagnosticVMOptions",
|
"-XX:+UnlockDiagnosticVMOptions",
|
||||||
"-XX:+WhiteBoxAPI",
|
"-XX:+WhiteBoxAPI",
|
||||||
"-XX:-TransmitErrorReport",
|
"-XX:-TransmitErrorReport",
|
||||||
|
"-XX:-CreateMinidumpOnCrash",
|
||||||
"-Xmx32m",
|
"-Xmx32m",
|
||||||
"AssertSafepointCheckConsistency1",
|
"AssertSafepointCheckConsistency1",
|
||||||
"test");
|
"test");
|
||||||
|
@ -55,5 +56,3 @@ public class AssertSafepointCheckConsistency1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ public class AssertSafepointCheckConsistency2 {
|
||||||
"-XX:+UnlockDiagnosticVMOptions",
|
"-XX:+UnlockDiagnosticVMOptions",
|
||||||
"-XX:+WhiteBoxAPI",
|
"-XX:+WhiteBoxAPI",
|
||||||
"-XX:-TransmitErrorReport",
|
"-XX:-TransmitErrorReport",
|
||||||
|
"-XX:-CreateMinidumpOnCrash",
|
||||||
"-Xmx32m",
|
"-Xmx32m",
|
||||||
"AssertSafepointCheckConsistency2",
|
"AssertSafepointCheckConsistency2",
|
||||||
"test");
|
"test");
|
||||||
|
|
|
@ -47,6 +47,7 @@ public class AssertSafepointCheckConsistency3 {
|
||||||
"-XX:+UnlockDiagnosticVMOptions",
|
"-XX:+UnlockDiagnosticVMOptions",
|
||||||
"-XX:+WhiteBoxAPI",
|
"-XX:+WhiteBoxAPI",
|
||||||
"-XX:-TransmitErrorReport",
|
"-XX:-TransmitErrorReport",
|
||||||
|
"-XX:-CreateMinidumpOnCrash",
|
||||||
"-Xmx32m",
|
"-Xmx32m",
|
||||||
"AssertSafepointCheckConsistency3",
|
"AssertSafepointCheckConsistency3",
|
||||||
"test");
|
"test");
|
||||||
|
|
|
@ -47,6 +47,7 @@ public class AssertSafepointCheckConsistency4 {
|
||||||
"-XX:+UnlockDiagnosticVMOptions",
|
"-XX:+UnlockDiagnosticVMOptions",
|
||||||
"-XX:+WhiteBoxAPI",
|
"-XX:+WhiteBoxAPI",
|
||||||
"-XX:-TransmitErrorReport",
|
"-XX:-TransmitErrorReport",
|
||||||
|
"-XX:-CreateMinidumpOnCrash",
|
||||||
"-Xmx32m",
|
"-Xmx32m",
|
||||||
"AssertSafepointCheckConsistency4",
|
"AssertSafepointCheckConsistency4",
|
||||||
"test");
|
"test");
|
||||||
|
|
114
hotspot/test/runtime/Thread/Fibonacci.java
Normal file
114
hotspot/test/runtime/Thread/Fibonacci.java
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, 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 Calculates Fibonacci numbers "recursively" via threads and compares
|
||||||
|
* the result with the classical calculation.
|
||||||
|
* This test is skipped on 32-bit Windows: limited virtual space on Win-32
|
||||||
|
* make this test inherently unstable on Windows with 32-bit VM data model.
|
||||||
|
* @requires !(os.family == "windows" & sun.arch.data.model == "32")
|
||||||
|
* @library /testlibrary
|
||||||
|
* @run main Fibonacci 15
|
||||||
|
*/
|
||||||
|
|
||||||
|
import com.oracle.java.testlibrary.Asserts;
|
||||||
|
|
||||||
|
public class Fibonacci extends Thread {
|
||||||
|
private int index;
|
||||||
|
private int value;
|
||||||
|
private Fibonacci left;
|
||||||
|
private Fibonacci right;
|
||||||
|
|
||||||
|
public Fibonacci(int i) {
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (index == 0 || index == 1) {
|
||||||
|
// base cases, 0 Fibonacci number = 0, 1 Fibonacci number = 1
|
||||||
|
value = index;
|
||||||
|
} else {
|
||||||
|
// inductive cases
|
||||||
|
left = new Fibonacci(index - 2);
|
||||||
|
right = new Fibonacci(index - 1);
|
||||||
|
left.start();
|
||||||
|
right.start();
|
||||||
|
try {
|
||||||
|
left.join();
|
||||||
|
right.join();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new Error("InterruptedException for index " + index, e);
|
||||||
|
}
|
||||||
|
// compute and terminate
|
||||||
|
value = left.getValue() + right.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int traditionalFibonacci(int n) {
|
||||||
|
int n1 = 0, n2 = 1, nn = 0;
|
||||||
|
|
||||||
|
if (n == 0 || n == 1) {
|
||||||
|
nn = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < n; ++i) {
|
||||||
|
nn = n2 + n1;
|
||||||
|
n1 = n2;
|
||||||
|
n2 = nn;
|
||||||
|
}
|
||||||
|
return nn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Error,AssertionError {
|
||||||
|
int expected;
|
||||||
|
int number;
|
||||||
|
Fibonacci recursiveFibonacci;
|
||||||
|
|
||||||
|
if (args.length != 1) {
|
||||||
|
throw new Error("Error: args.length must be 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
number = Integer.parseInt(args[0]);
|
||||||
|
recursiveFibonacci = new Fibonacci(number);
|
||||||
|
|
||||||
|
recursiveFibonacci.start();
|
||||||
|
try {
|
||||||
|
recursiveFibonacci.join();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new Error("InterruptedException in main thread", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
expected = traditionalFibonacci(number);
|
||||||
|
|
||||||
|
System.out.println("Fibonacci[" + number + "] = " + expected);
|
||||||
|
|
||||||
|
Asserts.assertEQ(recursiveFibonacci.getValue(), expected,
|
||||||
|
"Unexpected calculated value: " + recursiveFibonacci.getValue() + " expected " + expected );
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2013, 2015, 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
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
package sun.hotspot.tools.ctw;
|
package sun.hotspot.tools.ctw;
|
||||||
|
|
||||||
import sun.management.ManagementFactoryHelper;
|
import java.lang.management.ManagementFactory;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
@ -55,7 +55,7 @@ public class CompileTheWorld {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
if (ManagementFactoryHelper.getCompilationMXBean() == null) {
|
if (ManagementFactory.getCompilationMXBean() == null) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"CTW can not work in interpreted mode");
|
"CTW can not work in interpreted mode");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2013, 2015, 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,7 +24,7 @@
|
||||||
package sun.hotspot.tools.ctw;
|
package sun.hotspot.tools.ctw;
|
||||||
|
|
||||||
import com.sun.management.HotSpotDiagnosticMXBean;
|
import com.sun.management.HotSpotDiagnosticMXBean;
|
||||||
import sun.management.ManagementFactoryHelper;
|
import java.lang.management.ManagementFactory;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
@ -160,7 +160,7 @@ public class Utils {
|
||||||
public static String getVMOption(String name) {
|
public static String getVMOption(String name) {
|
||||||
String result;
|
String result;
|
||||||
HotSpotDiagnosticMXBean diagnostic
|
HotSpotDiagnosticMXBean diagnostic
|
||||||
= ManagementFactoryHelper.getDiagnosticMXBean();
|
= ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
|
||||||
result = diagnostic.getVMOption(name).getValue();
|
result = diagnostic.getVMOption(name).getValue();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue