annotate hotspot/src/share/vm/code/debugInfoRec.cpp @ 36602:3ab2b2853c57

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