1 /*
   2  * Copyright (c) 2015, 2019, 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 "classfile/javaClasses.hpp"
  27 #include "classfile/javaClasses.inline.hpp"
  28 #include "classfile/vmSymbols.hpp"
  29 #include "logging/log.hpp"
  30 #include "logging/logStream.hpp"
  31 #include "memory/oopFactory.hpp"
  32 #include "memory/universe.hpp"
  33 #include "oops/oop.inline.hpp"
  34 #include "oops/objArrayOop.inline.hpp"
  35 #include "prims/stackwalk.hpp"
  36 #include "runtime/globals.hpp"
  37 #include "runtime/handles.inline.hpp"
  38 #include "runtime/javaCalls.hpp"
  39 #include "runtime/thread.inline.hpp"
  40 #include "runtime/vframe.inline.hpp"
  41 #include "utilities/globalDefinitions.hpp"
  42 
  43 // setup and cleanup actions
  44 BaseFrameStream::BaseFrameStream(JavaThread* thread, Handle continuation) 
  45   : _thread(thread), _continuation(continuation), _anchor(0L) {
  46     assert (thread != NULL, "");
  47 }
  48 
  49 void BaseFrameStream::setup_magic_on_entry(objArrayHandle frames_array) {
  50   frames_array->obj_at_put(magic_pos, _thread->threadObj());
  51   _anchor = address_value();
  52   assert(check_magic(frames_array), "invalid magic");
  53 }
  54 
  55 bool BaseFrameStream::check_magic(objArrayHandle frames_array) {
  56   oop   m1 = frames_array->obj_at(magic_pos);
  57   jlong m2 = _anchor;
  58   if (oopDesc::equals(m1, _thread->threadObj()) && m2 == address_value())  return true;
  59   return false;
  60 }
  61 
  62 bool BaseFrameStream::cleanup_magic_on_exit(objArrayHandle frames_array) {
  63   bool ok = check_magic(frames_array);
  64   frames_array->obj_at_put(magic_pos, NULL);
  65   _anchor = 0L;
  66   return ok;
  67 }
  68 
  69 void BaseFrameStream::set_continuation(Handle cont) {
  70   // ensure that the lifetime of the handle is that of the entire walk
  71   // This actually also sets a copy of the handle in the RegisterMap,
  72   // but that's OK, because we want them to be the same, anyway.
  73   // (although we don't rely on this sharing, and set the other copy again)
  74   // tty->print_cr("-- BaseFrameStream::set_continuation: %p", (oopDesc*)cont());
  75   *(_continuation.raw_value()) = cont();
  76 }
  77 
  78 // static inline Handle continuation_of(Handle cont_or_scope) {
  79 //   return (cont_or_scope.not_null() && cont_or_scope()->is_a(SystemDictionary::Continuation_klass()))
  80 //             ? cont_or_scope
  81 //             : Handle();
  82 // }
  83 
  84 // static inline Handle continuationScope_of(JavaThread* thread, Handle cont_or_scope) {
  85 //   if (cont_or_scope.is_null() || cont_or_scope()->is_a(SystemDictionary::ContinuationScope_klass()))
  86 //     return cont_or_scope;
  87 //   assert (cont_or_scope()->is_a(SystemDictionary::Continuation_klass()), "must be");
  88 //   return Handle(thread, Continuation::continuation_scope(cont_or_scope()));
  89 // }
  90 
  91 JavaFrameStream::JavaFrameStream(JavaThread* thread, int mode, Handle cont_scope, Handle cont)
  92   : BaseFrameStream(thread, cont), 
  93    _vfst(cont.is_null()
  94       ? vframeStream(thread, cont_scope)
  95       : vframeStream(cont)) {
  96   _need_method_info = StackWalk::need_method_info(mode);
  97 }
  98 
  99 LiveFrameStream::LiveFrameStream(JavaThread* thread, RegisterMap* rm, Handle cont_scope, Handle cont)
 100    : BaseFrameStream(thread, cont), _cont_scope(cont_scope),
 101     _cont(cont.not_null() ? cont : Handle(thread, thread->last_continuation())) {
 102      
 103     _map = rm;
 104     if (cont.is_null()) {
 105       _jvf  = thread->last_java_vframe(rm);
 106       // _cont = Handle(thread, thread->last_continuation());
 107     } else {
 108       _jvf  = Continuation::has_last_Java_frame(cont) ? Continuation::last_java_vframe(cont, rm) : NULL;
 109       // _cont = cont;
 110     }
 111 }
 112 
 113 void JavaFrameStream::set_continuation(Handle cont) {
 114   BaseFrameStream::set_continuation(cont);
 115 
 116   _vfst = vframeStream(continuation()); // we must not use the handle argument (lifetime; see BaseFrameStream::set_continuation)
 117 }
 118 
 119 void LiveFrameStream::set_continuation(Handle cont) {
 120   BaseFrameStream::set_continuation(cont);
 121 
 122   _jvf = Continuation::last_java_vframe(continuation(), _map); // we must not use the handle argument (lifetime; see BaseFrameStream::set_continuation)
 123   _cont = continuation(); // *(_cont.raw_value()) = cont(); // preserve handle
 124   tty->print_cr("-- LiveFrameStream::set_continuation: %p", (oopDesc*)_cont());
 125 }
 126 
 127 void JavaFrameStream::next() { 
 128   _vfst.next(); 
 129 }
 130 
 131 void LiveFrameStream::next() {
 132   assert (_cont_scope.is_null() || _cont.not_null(), "must be");
 133   if (_cont.not_null() && Continuation::is_continuation_entry_frame(_jvf->fr(), _jvf->register_map())) {
 134     oop cont = _cont();
 135     oop scope = java_lang_Continuation::scope(cont);
 136 
 137     *(_cont.raw_value()) = java_lang_Continuation::parent(cont);
 138     
 139     if (_cont_scope.not_null() && oopDesc::equals(scope, _cont_scope())) {
 140       assert (Continuation::is_frame_in_continuation(_jvf->fr(), cont), "must be");
 141       _jvf = NULL;
 142       return;
 143     }
 144   }
 145   assert (!Continuation::is_scope_bottom(_cont_scope(), _jvf->fr(), _jvf->register_map()), "");
 146   
 147   _jvf = _jvf->java_sender();
 148 }
 149 
 150 // Returns the BaseFrameStream for the current stack being traversed.
 151 //
 152 // Parameters:
 153 //  thread         Current Java thread.
 154 //  magic          Magic value used for each stack walking
 155 //  frames_array   User-supplied buffers.  The 0th element is reserved
 156 //                 for this BaseFrameStream to use
 157 //
 158 BaseFrameStream* BaseFrameStream::from_current(JavaThread* thread, jlong magic,
 159                                                objArrayHandle frames_array)
 160 {
 161   assert(thread != NULL && thread->is_Java_thread(), "");
 162   oop m1 = frames_array->obj_at(magic_pos);
 163   if (!oopDesc::equals(m1, thread->threadObj())) return NULL;
 164   if (magic == 0L)                    return NULL;
 165   BaseFrameStream* stream = (BaseFrameStream*) (intptr_t) magic;
 166   if (!stream->is_valid_in(thread, frames_array))   return NULL;
 167   return stream;
 168 }
 169 
 170 // Unpacks one or more frames into user-supplied buffers.
 171 // Updates the end index, and returns the number of unpacked frames.
 172 // Always start with the existing vfst.method and bci.
 173 // Do not call vfst.next to advance over the last returned value.
 174 // In other words, do not leave any stale data in the vfst.
 175 //
 176 // Parameters:
 177 //   mode             Restrict which frames to be decoded.
 178 //   BaseFrameStream  stream of frames
 179 //   max_nframes      Maximum number of frames to be filled.
 180 //   start_index      Start index to the user-supplied buffers.
 181 //   frames_array     Buffer to store Class or StackFrame in, starting at start_index.
 182 //                    frames array is a Class<?>[] array when only getting caller
 183 //                    reference, and a StackFrameInfo[] array (or derivative)
 184 //                    otherwise. It should never be null.
 185 //   end_index        End index to the user-supplied buffers with unpacked frames.
 186 //
 187 // Returns the number of frames whose information was transferred into the buffers.
 188 //
 189 int StackWalk::fill_in_frames(jlong mode, BaseFrameStream& stream,
 190                               int max_nframes, int start_index,
 191                               objArrayHandle  frames_array,
 192                               int& end_index, TRAPS) {
 193   log_debug(stackwalk)("fill_in_frames limit=%d start=%d frames length=%d",
 194                        max_nframes, start_index, frames_array->length());
 195   assert(max_nframes > 0, "invalid max_nframes");
 196   assert(start_index + max_nframes <= frames_array->length(), "oob");
 197 
 198   int frames_decoded = 0;
 199   for (; !stream.at_end(); stream.next()) {
 200     Method* method = stream.method();
 201 
 202     if (method == NULL) continue;
 203 
 204     // skip hidden frames for default StackWalker option (i.e. SHOW_HIDDEN_FRAMES
 205     // not set) and when StackWalker::getCallerClass is called
 206     if (!ShowHiddenFrames && (skip_hidden_frames(mode) || get_caller_class(mode))) {
 207       if (method->is_hidden()) {
 208         LogTarget(Debug, stackwalk) lt;
 209         if (lt.is_enabled()) {
 210           ResourceMark rm(THREAD);
 211           LogStream ls(lt);
 212           ls.print("  hidden method: ");
 213           method->print_short_name(&ls);
 214           ls.cr();
 215         }
 216         continue;
 217       }
 218     }
 219 
 220     int index = end_index++;
 221     LogTarget(Debug, stackwalk) lt;
 222     if (lt.is_enabled()) {
 223       ResourceMark rm(THREAD);
 224       LogStream ls(lt);
 225       ls.print("  %d: frame method: ", index);
 226       method->print_short_name(&ls);
 227       ls.print_cr(" bci=%d", stream.bci());
 228     }
 229 
 230     if (!need_method_info(mode) && get_caller_class(mode) &&
 231           index == start_index && method->caller_sensitive()) {
 232       ResourceMark rm(THREAD);
 233       THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(),
 234         err_msg("StackWalker::getCallerClass called from @CallerSensitive '%s' method",
 235                 method->external_name()));
 236     }
 237     // fill in StackFrameInfo and initialize MemberName
 238     stream.fill_frame(index, frames_array, method, CHECK_0);
 239 
 240     if (lt.is_enabled()) {
 241       ResourceMark rm(THREAD);
 242       LogStream ls(lt);
 243       ls.print("  %d: done frame method: ", index);
 244       method->print_short_name(&ls);
 245     }
 246 
 247     if (++frames_decoded >= max_nframes)  break;
 248   }
 249   log_debug(stackwalk)("fill_in_frames done frames_decoded=%d at_end=%d", frames_decoded, stream.at_end());
 250 
 251   return frames_decoded;
 252 }
 253 
 254 // Fill in the LiveStackFrameInfo at the given index in frames_array
 255 void LiveFrameStream::fill_frame(int index, objArrayHandle  frames_array,
 256                                  const methodHandle& method, TRAPS) {
 257   HandleMark hm(THREAD);
 258   Handle stackFrame(THREAD, frames_array->obj_at(index));
 259   fill_live_stackframe(stackFrame, method, CHECK);
 260 }
 261 
 262 // Fill in the StackFrameInfo at the given index in frames_array
 263 void JavaFrameStream::fill_frame(int index, objArrayHandle  frames_array,
 264                                  const methodHandle& method, TRAPS) {
 265   if (_need_method_info) {
 266     HandleMark hm(THREAD);
 267     Handle stackFrame(THREAD, frames_array->obj_at(index));
 268     fill_stackframe(stackFrame, method, CHECK);
 269   } else {
 270     frames_array->obj_at_put(index, method->method_holder()->java_mirror());
 271   }
 272 }
 273 
 274 // Create and return a LiveStackFrame.PrimitiveSlot (if needed) for the
 275 // StackValue at the given index. 'type' is expected to be T_INT, T_LONG,
 276 // T_OBJECT, or T_CONFLICT.
 277 oop LiveFrameStream::create_primitive_slot_instance(StackValueCollection* values,
 278                                                     int i, BasicType type, TRAPS) {
 279   Klass* k = SystemDictionary::resolve_or_null(vmSymbols::java_lang_LiveStackFrameInfo(), CHECK_NULL);
 280   InstanceKlass* ik = InstanceKlass::cast(k);
 281 
 282   JavaValue result(T_OBJECT);
 283   JavaCallArguments args;
 284   Symbol* signature = NULL;
 285 
 286   // ## TODO: type is only available in LocalVariable table, if present.
 287   // ## StackValue type is T_INT or T_OBJECT (or converted to T_LONG on 64-bit)
 288   switch (type) {
 289     case T_INT:
 290       args.push_int(values->int_at(i));
 291       signature = vmSymbols::asPrimitive_int_signature();
 292       break;
 293 
 294     case T_LONG:
 295       args.push_long(values->long_at(i));
 296       signature = vmSymbols::asPrimitive_long_signature();
 297       break;
 298 
 299     case T_FLOAT:
 300     case T_DOUBLE:
 301     case T_BYTE:
 302     case T_SHORT:
 303     case T_CHAR:
 304     case T_BOOLEAN:
 305       THROW_MSG_(vmSymbols::java_lang_InternalError(), "Unexpected StackValue type", NULL);
 306 
 307     case T_OBJECT:
 308       return values->obj_at(i)();
 309 
 310     case T_CONFLICT:
 311       // put a non-null slot
 312       #ifdef _LP64
 313         args.push_long(0);
 314         signature = vmSymbols::asPrimitive_long_signature();
 315       #else
 316         args.push_int(0);
 317         signature = vmSymbols::asPrimitive_int_signature();
 318       #endif
 319 
 320       break;
 321 
 322     default: ShouldNotReachHere();
 323   }
 324   JavaCalls::call_static(&result,
 325                          ik,
 326                          vmSymbols::asPrimitive_name(),
 327                          signature,
 328                          &args,
 329                          CHECK_NULL);
 330   return (instanceOop) result.get_jobject();
 331 }
 332 
 333 objArrayHandle LiveFrameStream::values_to_object_array(StackValueCollection* values, TRAPS) {
 334   objArrayHandle empty;
 335   int length = values->size();
 336   objArrayOop array_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(),
 337                                                    length, CHECK_(empty));
 338   objArrayHandle array_h(THREAD, array_oop);
 339   for (int i = 0; i < values->size(); i++) {
 340     StackValue* st = values->at(i);
 341     BasicType type = st->type();
 342     int index = i;
 343 #ifdef _LP64
 344     if (type != T_OBJECT && type != T_CONFLICT) {
 345         intptr_t ret = st->get_int(); // read full 64-bit slot
 346         type = T_LONG;                // treat as long
 347         index--;                      // undo +1 in StackValueCollection::long_at
 348     }
 349 #endif
 350     oop obj = create_primitive_slot_instance(values, index, type, CHECK_(empty));
 351     if (obj != NULL) {
 352       array_h->obj_at_put(i, obj);
 353     }
 354   }
 355   return array_h;
 356 }
 357 
 358 objArrayHandle LiveFrameStream::monitors_to_object_array(GrowableArray<MonitorInfo*>* monitors, TRAPS) {
 359   int length = monitors->length();
 360   objArrayOop array_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(),
 361                                                    length, CHECK_(objArrayHandle()));
 362   objArrayHandle array_h(THREAD, array_oop);
 363   for (int i = 0; i < length; i++) {
 364     MonitorInfo* monitor = monitors->at(i);
 365     array_h->obj_at_put(i, monitor->owner());
 366   }
 367   return array_h;
 368 }
 369 
 370 // Fill StackFrameInfo with bci and initialize memberName
 371 void BaseFrameStream::fill_stackframe(Handle stackFrame, const methodHandle& method, TRAPS) {
 372   java_lang_StackFrameInfo::set_method_and_bci(stackFrame, method, bci(), cont(), THREAD);
 373 }
 374 
 375 // Fill LiveStackFrameInfo with locals, monitors, and expressions
 376 void LiveFrameStream::fill_live_stackframe(Handle stackFrame,
 377                                            const methodHandle& method, TRAPS) {
 378   fill_stackframe(stackFrame, method, CHECK);
 379   if (_jvf != NULL) {
 380     StackValueCollection* locals = _jvf->locals();
 381     StackValueCollection* expressions = _jvf->expressions();
 382     GrowableArray<MonitorInfo*>* monitors = _jvf->monitors();
 383 
 384     int mode = 0;
 385     if (_jvf->is_interpreted_frame()) {
 386       mode = MODE_INTERPRETED;
 387     } else if (_jvf->is_compiled_frame()) {
 388       mode = MODE_COMPILED;
 389     }
 390 
 391     if (!locals->is_empty()) {
 392       objArrayHandle locals_h = values_to_object_array(locals, CHECK);
 393       java_lang_LiveStackFrameInfo::set_locals(stackFrame(), locals_h());
 394     }
 395     if (!expressions->is_empty()) {
 396       objArrayHandle expressions_h = values_to_object_array(expressions, CHECK);
 397       java_lang_LiveStackFrameInfo::set_operands(stackFrame(), expressions_h());
 398     }
 399     if (monitors->length() > 0) {
 400       objArrayHandle monitors_h = monitors_to_object_array(monitors, CHECK);
 401       java_lang_LiveStackFrameInfo::set_monitors(stackFrame(), monitors_h());
 402     }
 403     java_lang_LiveStackFrameInfo::set_mode(stackFrame(), mode);
 404   }
 405 }
 406 
 407 // Begins stack walking.
 408 //
 409 // Parameters:
 410 //   stackStream    StackStream object
 411 //   mode           Stack walking mode.
 412 //   skip_frames    Number of frames to be skipped.
 413 //   cont_scope     Continuation scope to walk (if not in this scope, we'll walk all the way).
 414 //   frame_count    Number of frames to be traversed.
 415 //   start_index    Start index to the user-supplied buffers.
 416 //   frames_array   Buffer to store StackFrame in, starting at start_index.
 417 //                  frames array is a Class<?>[] array when only getting caller
 418 //                  reference, and a StackFrameInfo[] array (or derivative)
 419 //                  otherwise. It should never be null.
 420 //
 421 // Returns Object returned from AbstractStackWalker::doStackWalk call.
 422 //
 423 oop StackWalk::walk(Handle stackStream, jlong mode, int skip_frames, Handle cont_scope, Handle cont, 
 424                     int frame_count, int start_index, objArrayHandle frames_array,
 425                     TRAPS) {
 426   ResourceMark rm(THREAD);
 427   HandleMark hm(THREAD); // needed to store a continuation in the RegisterMap
 428 
 429   JavaThread* jt = (JavaThread*)THREAD;
 430   log_debug(stackwalk)("Start walking: mode " JLONG_FORMAT " skip %d frames batch size %d", mode, skip_frames, frame_count);
 431   LogTarget(Debug, stackwalk) lt;
 432   if (lt.is_enabled()) {
 433     ResourceMark rm(THREAD);
 434     LogStream ls(lt);
 435     ls.print("cont_scope: ");
 436     cont_scope()->print_on(&ls);
 437     ls.cr();
 438   }
 439 
 440   if (frames_array.is_null()) {
 441     THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", NULL);
 442   }
 443 
 444   // Setup traversal onto my stack.
 445   if (live_frame_info(mode)) {
 446     assert (use_frames_array(mode), "Bad mode for get live frame");
 447     RegisterMap regMap(jt, true, true);
 448     LiveFrameStream stream(jt, &regMap, cont_scope, cont);
 449     return fetchFirstBatch(stream, stackStream, mode, skip_frames, frame_count,
 450                            start_index, frames_array, THREAD);
 451   } else {
 452     JavaFrameStream stream(jt, mode, cont_scope, cont);
 453     return fetchFirstBatch(stream, stackStream, mode, skip_frames, frame_count,
 454                            start_index, frames_array, THREAD);
 455   }
 456 }
 457 
 458 oop StackWalk::fetchFirstBatch(BaseFrameStream& stream, Handle stackStream,
 459                                jlong mode, int skip_frames, int frame_count,
 460                                int start_index, objArrayHandle frames_array, TRAPS) {
 461   methodHandle m_doStackWalk(THREAD, Universe::do_stack_walk_method());
 462 
 463   {
 464     Klass* stackWalker_klass = SystemDictionary::StackWalker_klass();
 465     Klass* abstractStackWalker_klass = SystemDictionary::AbstractStackWalker_klass();
 466     while (!stream.at_end()) {
 467       InstanceKlass* ik = stream.method()->method_holder();
 468       if (ik != stackWalker_klass &&
 469             ik != abstractStackWalker_klass && ik->super() != abstractStackWalker_klass)  {
 470         break;
 471       }
 472 
 473       LogTarget(Debug, stackwalk) lt;
 474       if (lt.is_enabled()) {
 475         ResourceMark rm(THREAD);
 476         LogStream ls(lt);
 477         ls.print("  skip ");
 478         stream.method()->print_short_name(&ls);
 479         ls.cr();
 480       }
 481       stream.next();
 482     }
 483 
 484     // stack frame has been traversed individually and resume stack walk
 485     // from the stack frame at depth == skip_frames.
 486     for (int n=0; n < skip_frames && !stream.at_end(); stream.next(), n++) {
 487       LogTarget(Debug, stackwalk) lt;
 488       if (lt.is_enabled()) {
 489         ResourceMark rm(THREAD);
 490         LogStream ls(lt);
 491         ls.print("  skip ");
 492         stream.method()->print_short_name(&ls);
 493         ls.cr();
 494       }
 495     }
 496   }
 497 
 498   int end_index = start_index;
 499   int numFrames = 0;
 500   if (!stream.at_end()) {
 501     numFrames = fill_in_frames(mode, stream, frame_count, start_index,
 502                                frames_array, end_index, CHECK_NULL);
 503     if (numFrames < 1) {
 504       THROW_MSG_(vmSymbols::java_lang_InternalError(), "stack walk: decode failed", NULL);
 505     }
 506   }
 507 
 508   // JVM_CallStackWalk walks the stack and fills in stack frames, then calls to
 509   // Java method java.lang.StackStreamFactory.AbstractStackWalker::doStackWalk
 510   // which calls the implementation to consume the stack frames.
 511   // When JVM_CallStackWalk returns, it invalidates the stack stream.
 512   JavaValue result(T_OBJECT);
 513   JavaCallArguments args(stackStream);
 514   args.push_long(stream.address_value());
 515   args.push_int(skip_frames);
 516   args.push_int(frame_count);
 517   args.push_int(start_index);
 518   args.push_int(end_index);
 519 
 520   // Link the thread and vframe stream into the callee-visible object
 521   stream.setup_magic_on_entry(frames_array);
 522 
 523   JavaCalls::call(&result, m_doStackWalk, &args, THREAD);
 524 
 525   // Do this before anything else happens, to disable any lingering stream objects
 526   bool ok = stream.cleanup_magic_on_exit(frames_array);
 527 
 528   // Throw pending exception if we must
 529   (void) (CHECK_NULL);
 530 
 531   if (!ok) {
 532     THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers on exit", NULL);
 533   }
 534 
 535   // Return normally
 536   return (oop)result.get_jobject();
 537 }
 538 
 539 // Walk the next batch of stack frames
 540 //
 541 // Parameters:
 542 //   stackStream    StackStream object
 543 //   mode           Stack walking mode.
 544 //   magic          Must be valid value to continue the stack walk
 545 //   frame_count    Number of frames to be decoded.
 546 //   start_index    Start index to the user-supplied buffers.
 547 //   frames_array   Buffer to store StackFrame in, starting at start_index.
 548 //
 549 // Returns the end index of frame filled in the buffer.
 550 //
 551 jint StackWalk::fetchNextBatch(Handle stackStream, jlong mode, jlong magic,
 552                                int frame_count, int start_index, 
 553                                objArrayHandle frames_array,
 554                                TRAPS)
 555 {
 556   JavaThread* jt = (JavaThread*)THREAD;
 557   BaseFrameStream* existing_stream = BaseFrameStream::from_current(jt, magic, frames_array);
 558   if (existing_stream == NULL) {
 559     THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers", 0L);
 560   }
 561 
 562   if (frames_array.is_null()) {
 563     THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", 0L);
 564   }
 565 
 566   log_debug(stackwalk)("StackWalk::fetchNextBatch frame_count %d existing_stream "
 567                        PTR_FORMAT " start %d frames %d",
 568                        frame_count, p2i(existing_stream), start_index, frames_array->length());
 569   int end_index = start_index;
 570   if (frame_count <= 0) {
 571     return end_index;        // No operation.
 572   }
 573 
 574   int count = frame_count + start_index;
 575   assert (frames_array->length() >= count, "not enough space in buffers");
 576 
 577   BaseFrameStream& stream = (*existing_stream);
 578   if (!stream.at_end()) {
 579     stream.next(); // advance past the last frame decoded in previous batch
 580     if (!stream.at_end()) {
 581       int n = fill_in_frames(mode, stream, frame_count, start_index,
 582                              frames_array, end_index, CHECK_0);
 583       if (n < 1) {
 584         THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: later decode failed", 0L);
 585       }
 586       return end_index;
 587     }
 588   }
 589   return end_index;
 590 }
 591 
 592 void StackWalk::setContinuation(Handle stackStream, jlong magic, objArrayHandle frames_array, Handle cont, TRAPS) {
 593   JavaThread* jt = (JavaThread*)THREAD;
 594 
 595   if (frames_array.is_null()) {
 596     THROW_MSG(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL");
 597   }
 598 
 599   BaseFrameStream* existing_stream = BaseFrameStream::from_current(jt, magic, frames_array);
 600   if (existing_stream == NULL) {
 601     THROW_MSG(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers");
 602   }
 603 
 604   existing_stream->set_continuation(cont);
 605 }