1 | /* |
2 | * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. |
8 | * |
9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
12 | * version 2 for more details (a copy is included in the LICENSE file that |
13 | * accompanied this code). |
14 | * |
15 | * You should have received a copy of the GNU General Public License version |
16 | * 2 along with this work; if not, write to the Free Software Foundation, |
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
18 | * |
19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
20 | * or visit www.oracle.com if you need additional information or have any |
21 | * questions. |
22 | * |
23 | */ |
24 | |
25 | #include "precompiled.hpp" |
26 | #include "code/debugInfoRec.hpp" |
27 | #include "code/scopeDesc.hpp" |
28 | #include "prims/jvmtiExport.hpp" |
29 | |
30 | // Private definition. |
31 | // There is one DIR_Chunk for each scope and values array. |
32 | // A chunk can potentially be used more than once. |
33 | // We keep track of these chunks in order to detect |
34 | // repetition and enable sharing. |
35 | class DIR_Chunk { |
36 | private: |
37 | int _offset; // location in the stream of this scope |
38 | int _length; // number of bytes in the stream |
39 | int _hash; // hash of stream bytes (for quicker reuse) |
40 | DebugInformationRecorder* _DIR; |
41 | |
42 | public: |
43 | int offset() { return _offset; } |
44 | |
45 | void* operator new(size_t ignore, DebugInformationRecorder* dir) throw() { |
46 | assert(ignore == sizeof(DIR_Chunk), "" ); |
47 | if (dir->_next_chunk >= dir->_next_chunk_limit) { |
48 | const int CHUNK = 100; |
49 | dir->_next_chunk = NEW_RESOURCE_ARRAY(DIR_Chunk, CHUNK); |
50 | dir->_next_chunk_limit = dir->_next_chunk + CHUNK; |
51 | } |
52 | return dir->_next_chunk++; |
53 | } |
54 | |
55 | DIR_Chunk(int offset, int length, DebugInformationRecorder* dir) { |
56 | _offset = offset; |
57 | _length = length; |
58 | _DIR = dir; |
59 | unsigned int hash = 0; |
60 | address p = dir->stream()->buffer() + _offset; |
61 | for (int i = 0; i < length; i++) { |
62 | if (i == 6) break; |
63 | hash *= 127; |
64 | hash += p[i]; |
65 | } |
66 | _hash = hash; |
67 | } |
68 | |
69 | DIR_Chunk* find_match(GrowableArray<DIR_Chunk*>* arr, |
70 | int start_index, |
71 | DebugInformationRecorder* dir) { |
72 | int end_index = arr->length(); |
73 | int hash = this->_hash, length = this->_length; |
74 | address buf = dir->stream()->buffer(); |
75 | for (int i = end_index; --i >= start_index; ) { |
76 | DIR_Chunk* that = arr->at(i); |
77 | if (hash == that->_hash && |
78 | length == that->_length && |
79 | 0 == memcmp(buf + this->_offset, buf + that->_offset, length)) { |
80 | return that; |
81 | } |
82 | } |
83 | return NULL; |
84 | } |
85 | |
86 | static int compare(DIR_Chunk* const & a, DIR_Chunk* const & b) { |
87 | if (b->_hash > a->_hash) { |
88 | return 1; |
89 | } |
90 | if (b->_hash < a->_hash) { |
91 | return -1; |
92 | } |
93 | if (b->_length > a->_length) { |
94 | return 1; |
95 | } |
96 | if (b->_length < a->_length) { |
97 | return -1; |
98 | } |
99 | address buf = a->_DIR->stream()->buffer(); |
100 | return memcmp(buf + b->_offset, buf + a->_offset, a->_length); |
101 | } |
102 | }; |
103 | |
104 | static inline bool compute_recording_non_safepoints() { |
105 | if (JvmtiExport::should_post_compiled_method_load() |
106 | && FLAG_IS_DEFAULT(DebugNonSafepoints)) { |
107 | // The default value of this flag is taken to be true, |
108 | // if JVMTI is looking at nmethod codes. |
109 | // We anticipate that JVMTI may wish to participate in profiling. |
110 | return true; |
111 | } |
112 | |
113 | // If the flag is set manually, use it, whether true or false. |
114 | // Otherwise, if JVMTI is not in the picture, use the default setting. |
115 | // (This is true in debug, just for the exercise, false in product mode.) |
116 | return DebugNonSafepoints; |
117 | } |
118 | |
119 | DebugInformationRecorder::DebugInformationRecorder(OopRecorder* oop_recorder) |
120 | : _recording_non_safepoints(compute_recording_non_safepoints()) |
121 | { |
122 | _pcs_size = 100; |
123 | _pcs = NEW_RESOURCE_ARRAY(PcDesc, _pcs_size); |
124 | _pcs_length = 0; |
125 | |
126 | _prev_safepoint_pc = PcDesc::lower_offset_limit; |
127 | |
128 | _stream = new DebugInfoWriteStream(this, 10 * K); |
129 | // make sure that there is no stream_decode_offset that is zero |
130 | _stream->write_byte((jbyte)0xFF); |
131 | |
132 | // make sure that we can distinguish the value "serialized_null" from offsets |
133 | assert(_stream->position() > serialized_null, "sanity" ); |
134 | |
135 | _oop_recorder = oop_recorder; |
136 | |
137 | _all_chunks = new GrowableArray<DIR_Chunk*>(300); |
138 | _next_chunk = _next_chunk_limit = NULL; |
139 | |
140 | add_new_pc_offset(PcDesc::lower_offset_limit); // sentinel record |
141 | |
142 | debug_only(_recording_state = rs_null); |
143 | } |
144 | |
145 | |
146 | void DebugInformationRecorder::add_oopmap(int pc_offset, OopMap* map) { |
147 | // !!!!! Preserve old style handling of oopmaps for now |
148 | _oopmaps->add_gc_map(pc_offset, map); |
149 | } |
150 | |
151 | void DebugInformationRecorder::add_safepoint(int pc_offset, OopMap* map) { |
152 | assert(!_oop_recorder->is_complete(), "not frozen yet" ); |
153 | // Store the new safepoint |
154 | |
155 | // Add the oop map |
156 | add_oopmap(pc_offset, map); |
157 | |
158 | add_new_pc_offset(pc_offset); |
159 | |
160 | assert(_recording_state == rs_null, "nesting of recording calls" ); |
161 | debug_only(_recording_state = rs_safepoint); |
162 | } |
163 | |
164 | void DebugInformationRecorder::add_non_safepoint(int pc_offset) { |
165 | assert(!_oop_recorder->is_complete(), "not frozen yet" ); |
166 | assert(_recording_non_safepoints, "must be recording non-safepoints" ); |
167 | |
168 | add_new_pc_offset(pc_offset); |
169 | |
170 | assert(_recording_state == rs_null, "nesting of recording calls" ); |
171 | debug_only(_recording_state = rs_non_safepoint); |
172 | } |
173 | |
174 | void DebugInformationRecorder::add_new_pc_offset(int pc_offset) { |
175 | assert(_pcs_length == 0 || last_pc()->pc_offset() < pc_offset, |
176 | "must specify a new, larger pc offset" ); |
177 | |
178 | // add the pcdesc |
179 | if (_pcs_length == _pcs_size) { |
180 | // Expand |
181 | int new_pcs_size = _pcs_size * 2; |
182 | PcDesc* new_pcs = NEW_RESOURCE_ARRAY(PcDesc, new_pcs_size); |
183 | for (int index = 0; index < _pcs_length; index++) { |
184 | new_pcs[index] = _pcs[index]; |
185 | } |
186 | _pcs_size = new_pcs_size; |
187 | _pcs = new_pcs; |
188 | } |
189 | assert(_pcs_size > _pcs_length, "There must be room for after expanding" ); |
190 | |
191 | _pcs[_pcs_length++] = PcDesc(pc_offset, DebugInformationRecorder::serialized_null, |
192 | DebugInformationRecorder::serialized_null); |
193 | } |
194 | |
195 | |
196 | int DebugInformationRecorder::serialize_monitor_values(GrowableArray<MonitorValue*>* monitors) { |
197 | if (monitors == NULL || monitors->is_empty()) return DebugInformationRecorder::serialized_null; |
198 | assert(_recording_state == rs_safepoint, "must be recording a safepoint" ); |
199 | int result = stream()->position(); |
200 | stream()->write_int(monitors->length()); |
201 | for (int index = 0; index < monitors->length(); index++) { |
202 | monitors->at(index)->write_on(stream()); |
203 | } |
204 | assert(result != serialized_null, "sanity" ); |
205 | |
206 | // (See comment below on DebugInformationRecorder::describe_scope.) |
207 | int shared_result = find_sharable_decode_offset(result); |
208 | if (shared_result != serialized_null) { |
209 | stream()->set_position(result); |
210 | result = shared_result; |
211 | } |
212 | |
213 | return result; |
214 | } |
215 | |
216 | |
217 | int DebugInformationRecorder::serialize_scope_values(GrowableArray<ScopeValue*>* values) { |
218 | if (values == NULL || values->is_empty()) return DebugInformationRecorder::serialized_null; |
219 | assert(_recording_state == rs_safepoint, "must be recording a safepoint" ); |
220 | int result = stream()->position(); |
221 | assert(result != serialized_null, "sanity" ); |
222 | stream()->write_int(values->length()); |
223 | for (int index = 0; index < values->length(); index++) { |
224 | values->at(index)->write_on(stream()); |
225 | } |
226 | |
227 | // (See comment below on DebugInformationRecorder::describe_scope.) |
228 | int shared_result = find_sharable_decode_offset(result); |
229 | if (shared_result != serialized_null) { |
230 | stream()->set_position(result); |
231 | result = shared_result; |
232 | } |
233 | |
234 | return result; |
235 | } |
236 | |
237 | |
238 | #ifndef PRODUCT |
239 | // These variables are put into one block to reduce relocations |
240 | // and make it simpler to print from the debugger. |
241 | static |
242 | struct dir_stats_struct { |
243 | int chunks_queried; |
244 | int chunks_shared; |
245 | int chunks_reshared; |
246 | int chunks_elided; |
247 | |
248 | void print() { |
249 | tty->print_cr("Debug Data Chunks: %d, shared %d+%d, non-SP's elided %d" , |
250 | chunks_queried, |
251 | chunks_shared, chunks_reshared, |
252 | chunks_elided); |
253 | } |
254 | } dir_stats; |
255 | #endif //PRODUCT |
256 | |
257 | |
258 | int DebugInformationRecorder::find_sharable_decode_offset(int stream_offset) { |
259 | NOT_PRODUCT(++dir_stats.chunks_queried); |
260 | int stream_length = stream()->position() - stream_offset; |
261 | assert(stream_offset != serialized_null, "should not be null" ); |
262 | assert(stream_length != 0, "should not be empty" ); |
263 | |
264 | DIR_Chunk* ns = new(this) DIR_Chunk(stream_offset, stream_length, this); |
265 | |
266 | DIR_Chunk* match = _all_chunks->insert_sorted<DIR_Chunk::compare>(ns); |
267 | if (match != ns) { |
268 | // Found an existing chunk |
269 | NOT_PRODUCT(++dir_stats.chunks_shared); |
270 | assert(ns+1 == _next_chunk, "" ); |
271 | _next_chunk = ns; |
272 | return match->offset(); |
273 | } else { |
274 | // Inserted this chunk, so nothing to do |
275 | return serialized_null; |
276 | } |
277 | } |
278 | |
279 | |
280 | // must call add_safepoint before: it sets PcDesc and this routine uses |
281 | // the last PcDesc set |
282 | void DebugInformationRecorder::describe_scope(int pc_offset, |
283 | const methodHandle& methodH, |
284 | ciMethod* method, |
285 | int bci, |
286 | bool reexecute, |
287 | bool rethrow_exception, |
288 | bool is_method_handle_invoke, |
289 | bool return_oop, |
290 | DebugToken* locals, |
291 | DebugToken* expressions, |
292 | DebugToken* monitors) { |
293 | assert(_recording_state != rs_null, "nesting of recording calls" ); |
294 | PcDesc* last_pd = last_pc(); |
295 | assert(last_pd->pc_offset() == pc_offset, "must be last pc" ); |
296 | int sender_stream_offset = last_pd->scope_decode_offset(); |
297 | // update the stream offset of current pc desc |
298 | int stream_offset = stream()->position(); |
299 | last_pd->set_scope_decode_offset(stream_offset); |
300 | |
301 | // Record flags into pcDesc. |
302 | last_pd->set_should_reexecute(reexecute); |
303 | last_pd->set_rethrow_exception(rethrow_exception); |
304 | last_pd->set_is_method_handle_invoke(is_method_handle_invoke); |
305 | last_pd->set_return_oop(return_oop); |
306 | |
307 | // serialize sender stream offest |
308 | stream()->write_int(sender_stream_offset); |
309 | |
310 | // serialize scope |
311 | Metadata* method_enc; |
312 | if (method != NULL) { |
313 | method_enc = method->constant_encoding(); |
314 | } else if (methodH.not_null()) { |
315 | method_enc = methodH(); |
316 | } else { |
317 | method_enc = NULL; |
318 | } |
319 | int method_enc_index = oop_recorder()->find_index(method_enc); |
320 | stream()->write_int(method_enc_index); |
321 | stream()->write_bci(bci); |
322 | assert(method == NULL || |
323 | (method->is_native() && bci == 0) || |
324 | (!method->is_native() && 0 <= bci && bci < method->code_size()) || |
325 | bci == -1, "illegal bci" ); |
326 | |
327 | // serialize the locals/expressions/monitors |
328 | stream()->write_int((intptr_t) locals); |
329 | stream()->write_int((intptr_t) expressions); |
330 | stream()->write_int((intptr_t) monitors); |
331 | |
332 | // Here's a tricky bit. We just wrote some bytes. |
333 | // Wouldn't it be nice to find that we had already |
334 | // written those same bytes somewhere else? |
335 | // If we get lucky this way, reset the stream |
336 | // and reuse the old bytes. By the way, this |
337 | // trick not only shares parent scopes, but also |
338 | // compresses equivalent non-safepoint PcDescs. |
339 | int shared_stream_offset = find_sharable_decode_offset(stream_offset); |
340 | if (shared_stream_offset != serialized_null) { |
341 | stream()->set_position(stream_offset); |
342 | last_pd->set_scope_decode_offset(shared_stream_offset); |
343 | } |
344 | } |
345 | |
346 | void DebugInformationRecorder::dump_object_pool(GrowableArray<ScopeValue*>* objects) { |
347 | guarantee( _pcs_length > 0, "safepoint must exist before describing scopes" ); |
348 | PcDesc* last_pd = &_pcs[_pcs_length-1]; |
349 | if (objects != NULL) { |
350 | for (int i = objects->length() - 1; i >= 0; i--) { |
351 | objects->at(i)->as_ObjectValue()->set_visited(false); |
352 | } |
353 | } |
354 | int offset = serialize_scope_values(objects); |
355 | last_pd->set_obj_decode_offset(offset); |
356 | } |
357 | |
358 | void DebugInformationRecorder::end_scopes(int pc_offset, bool is_safepoint) { |
359 | assert(_recording_state == (is_safepoint? rs_safepoint: rs_non_safepoint), |
360 | "nesting of recording calls" ); |
361 | debug_only(_recording_state = rs_null); |
362 | |
363 | // Try to compress away an equivalent non-safepoint predecessor. |
364 | // (This only works because we have previously recognized redundant |
365 | // scope trees and made them use a common scope_decode_offset.) |
366 | if (_pcs_length >= 2 && recording_non_safepoints()) { |
367 | PcDesc* last = last_pc(); |
368 | PcDesc* prev = prev_pc(); |
369 | // If prev is (a) not a safepoint and (b) has the same |
370 | // stream pointer, then it can be coalesced into the last. |
371 | // This is valid because non-safepoints are only sought |
372 | // with pc_desc_near, which (when it misses prev) will |
373 | // search forward until it finds last. |
374 | // In addition, it does not matter if the last PcDesc |
375 | // is for a safepoint or not. |
376 | if (_prev_safepoint_pc < prev->pc_offset() && prev->is_same_info(last)) { |
377 | assert(prev == last-1, "sane" ); |
378 | prev->set_pc_offset(pc_offset); |
379 | _pcs_length -= 1; |
380 | NOT_PRODUCT(++dir_stats.chunks_elided); |
381 | } |
382 | } |
383 | |
384 | // We have just recorded this safepoint. |
385 | // Remember it in case the previous paragraph needs to know. |
386 | if (is_safepoint) { |
387 | _prev_safepoint_pc = pc_offset; |
388 | } |
389 | } |
390 | |
391 | #ifdef ASSERT |
392 | bool DebugInformationRecorder::recorders_frozen() { |
393 | return _oop_recorder->is_complete() || _oop_recorder->is_complete(); |
394 | } |
395 | |
396 | void DebugInformationRecorder::mark_recorders_frozen() { |
397 | _oop_recorder->freeze(); |
398 | } |
399 | #endif // PRODUCT |
400 | |
401 | DebugToken* DebugInformationRecorder::create_scope_values(GrowableArray<ScopeValue*>* values) { |
402 | assert(!recorders_frozen(), "not frozen yet" ); |
403 | return (DebugToken*) (intptr_t) serialize_scope_values(values); |
404 | } |
405 | |
406 | |
407 | DebugToken* DebugInformationRecorder::create_monitor_values(GrowableArray<MonitorValue*>* monitors) { |
408 | assert(!recorders_frozen(), "not frozen yet" ); |
409 | return (DebugToken*) (intptr_t) serialize_monitor_values(monitors); |
410 | } |
411 | |
412 | |
413 | int DebugInformationRecorder::data_size() { |
414 | debug_only(mark_recorders_frozen()); // mark it "frozen" for asserts |
415 | return _stream->position(); |
416 | } |
417 | |
418 | |
419 | int DebugInformationRecorder::pcs_size() { |
420 | debug_only(mark_recorders_frozen()); // mark it "frozen" for asserts |
421 | if (last_pc()->pc_offset() != PcDesc::upper_offset_limit) |
422 | add_new_pc_offset(PcDesc::upper_offset_limit); |
423 | return _pcs_length * sizeof(PcDesc); |
424 | } |
425 | |
426 | |
427 | void DebugInformationRecorder::copy_to(nmethod* nm) { |
428 | nm->copy_scopes_data(stream()->buffer(), stream()->position()); |
429 | nm->copy_scopes_pcs(_pcs, _pcs_length); |
430 | } |
431 | |
432 | |
433 | void DebugInformationRecorder::verify(const nmethod* code) { |
434 | Unimplemented(); |
435 | } |
436 | |
437 | #ifndef PRODUCT |
438 | void DebugInformationRecorder::print_statistics() { |
439 | dir_stats.print(); |
440 | } |
441 | #endif //PRODUCT |
442 | |