31 #include "runtime/synchronizer.hpp" |
31 #include "runtime/synchronizer.hpp" |
32 #include "runtime/thread.hpp" |
32 #include "runtime/thread.hpp" |
33 #include "services/threadService.hpp" |
33 #include "services/threadService.hpp" |
34 #include "utilities/chunkedList.hpp" |
34 #include "utilities/chunkedList.hpp" |
35 |
35 |
36 volatile MetadataOnStackBuffer* MetadataOnStackMark::_used_buffers = NULL; |
36 MetadataOnStackBuffer* MetadataOnStackMark::_used_buffers = NULL; |
37 volatile MetadataOnStackBuffer* MetadataOnStackMark::_free_buffers = NULL; |
37 MetadataOnStackBuffer* MetadataOnStackMark::_free_buffers = NULL; |
38 |
38 |
|
39 MetadataOnStackBuffer* MetadataOnStackMark::_current_buffer = NULL; |
39 NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;) |
40 NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;) |
40 |
41 |
41 // Walk metadata on the stack and mark it so that redefinition doesn't delete |
42 // Walk metadata on the stack and mark it so that redefinition doesn't delete |
42 // it. Class unloading also walks the previous versions and might try to |
43 // it. Class unloading only deletes in-error class files, methods created by |
43 // delete it, so this class is used by class unloading also. |
44 // the relocator and dummy constant pools. None of these appear anywhere except |
44 MetadataOnStackMark::MetadataOnStackMark(bool visit_code_cache) { |
45 // in metadata Handles. |
|
46 MetadataOnStackMark::MetadataOnStackMark(bool redefinition_walk) { |
45 assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); |
47 assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); |
46 assert(_used_buffers == NULL, "sanity check"); |
48 assert(_used_buffers == NULL, "sanity check"); |
|
49 assert(!_is_active, "MetadataOnStackMarks do not nest"); |
47 NOT_PRODUCT(_is_active = true;) |
50 NOT_PRODUCT(_is_active = true;) |
48 |
51 |
49 Threads::metadata_do(Metadata::mark_on_stack); |
52 Threads::metadata_handles_do(Metadata::mark_on_stack); |
50 if (visit_code_cache) { |
53 |
|
54 if (redefinition_walk) { |
|
55 Threads::metadata_do(Metadata::mark_on_stack); |
51 CodeCache::alive_nmethods_do(nmethod::mark_on_stack); |
56 CodeCache::alive_nmethods_do(nmethod::mark_on_stack); |
|
57 CompileBroker::mark_on_stack(); |
|
58 JvmtiCurrentBreakpoints::metadata_do(Metadata::mark_on_stack); |
|
59 ThreadService::metadata_do(Metadata::mark_on_stack); |
52 } |
60 } |
53 CompileBroker::mark_on_stack(); |
|
54 JvmtiCurrentBreakpoints::metadata_do(Metadata::mark_on_stack); |
|
55 ThreadService::metadata_do(Metadata::mark_on_stack); |
|
56 } |
61 } |
57 |
62 |
58 MetadataOnStackMark::~MetadataOnStackMark() { |
63 MetadataOnStackMark::~MetadataOnStackMark() { |
59 assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); |
64 assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); |
60 // Unmark everything that was marked. Can't do the same walk because |
65 // Unmark everything that was marked. Can't do the same walk because |
61 // redefine classes messes up the code cache so the set of methods |
66 // redefine classes messes up the code cache so the set of methods |
62 // might not be the same. |
67 // might not be the same. |
|
68 retire_current_buffer(); |
63 |
69 |
64 retire_buffer_for_thread(Thread::current()); |
70 MetadataOnStackBuffer* buffer = _used_buffers; |
65 |
|
66 MetadataOnStackBuffer* buffer = const_cast<MetadataOnStackBuffer* >(_used_buffers); |
|
67 while (buffer != NULL) { |
71 while (buffer != NULL) { |
68 // Clear on stack state for all metadata. |
72 // Clear on stack state for all metadata. |
69 size_t size = buffer->size(); |
73 size_t size = buffer->size(); |
70 for (size_t i = 0; i < size; i++) { |
74 for (size_t i = 0; i < size; i++) { |
71 Metadata* md = buffer->at(i); |
75 Metadata* md = buffer->at(i); |
91 |
95 |
92 void MetadataOnStackMark::retire_buffer(MetadataOnStackBuffer* buffer) { |
96 void MetadataOnStackMark::retire_buffer(MetadataOnStackBuffer* buffer) { |
93 if (buffer == NULL) { |
97 if (buffer == NULL) { |
94 return; |
98 return; |
95 } |
99 } |
96 |
100 buffer->set_next_used(_used_buffers); |
97 MetadataOnStackBuffer* old_head; |
101 _used_buffers = buffer; |
98 |
|
99 do { |
|
100 old_head = const_cast<MetadataOnStackBuffer*>(_used_buffers); |
|
101 buffer->set_next_used(old_head); |
|
102 } while (Atomic::cmpxchg_ptr(buffer, &_used_buffers, old_head) != old_head); |
|
103 } |
102 } |
104 |
103 |
105 void MetadataOnStackMark::retire_buffer_for_thread(Thread* thread) { |
104 // Current buffer is full or we're ready to walk them, add it to the used list. |
106 retire_buffer(thread->metadata_on_stack_buffer()); |
105 void MetadataOnStackMark::retire_current_buffer() { |
107 thread->set_metadata_on_stack_buffer(NULL); |
106 retire_buffer(_current_buffer); |
|
107 _current_buffer = NULL; |
108 } |
108 } |
109 |
109 |
110 bool MetadataOnStackMark::has_buffer_for_thread(Thread* thread) { |
110 // Get buffer off free list. |
111 return thread->metadata_on_stack_buffer() != NULL; |
111 MetadataOnStackBuffer* MetadataOnStackMark::allocate_buffer() { |
112 } |
112 MetadataOnStackBuffer* allocated = _free_buffers; |
113 |
113 |
114 MetadataOnStackBuffer* MetadataOnStackMark::allocate_buffer() { |
114 if (allocated != NULL) { |
115 MetadataOnStackBuffer* allocated; |
115 _free_buffers = allocated->next_free(); |
116 MetadataOnStackBuffer* new_head; |
116 } |
117 |
|
118 do { |
|
119 allocated = const_cast<MetadataOnStackBuffer*>(_free_buffers); |
|
120 if (allocated == NULL) { |
|
121 break; |
|
122 } |
|
123 new_head = allocated->next_free(); |
|
124 } while (Atomic::cmpxchg_ptr(new_head, &_free_buffers, allocated) != allocated); |
|
125 |
117 |
126 if (allocated == NULL) { |
118 if (allocated == NULL) { |
127 allocated = new MetadataOnStackBuffer(); |
119 allocated = new MetadataOnStackBuffer(); |
128 } |
120 } |
129 |
121 |
131 |
123 |
132 return allocated; |
124 return allocated; |
133 } |
125 } |
134 |
126 |
135 // Record which objects are marked so we can unmark the same objects. |
127 // Record which objects are marked so we can unmark the same objects. |
136 void MetadataOnStackMark::record(Metadata* m, Thread* thread) { |
128 void MetadataOnStackMark::record(Metadata* m) { |
137 assert(_is_active, "metadata on stack marking is active"); |
129 assert(_is_active, "metadata on stack marking is active"); |
138 |
130 |
139 MetadataOnStackBuffer* buffer = thread->metadata_on_stack_buffer(); |
131 MetadataOnStackBuffer* buffer = _current_buffer; |
140 |
132 |
141 if (buffer != NULL && buffer->is_full()) { |
133 if (buffer != NULL && buffer->is_full()) { |
142 retire_buffer(buffer); |
134 retire_buffer(buffer); |
143 buffer = NULL; |
135 buffer = NULL; |
144 } |
136 } |
145 |
137 |
146 if (buffer == NULL) { |
138 if (buffer == NULL) { |
147 buffer = allocate_buffer(); |
139 buffer = allocate_buffer(); |
148 thread->set_metadata_on_stack_buffer(buffer); |
140 _current_buffer = buffer; |
149 } |
141 } |
150 |
142 |
151 buffer->push(m); |
143 buffer->push(m); |
152 } |
144 } |