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