1 /*
  2  * Copyright (c) 2021, 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/compiledMethod.hpp"
 27 #include "code/scopeDesc.hpp"
 28 #include "memory/memRegion.hpp"
 29 #include "oops/instanceStackChunkKlass.inline.hpp"
 30 #include "oops/oop.inline.hpp"
 31 #include "oops/stackChunkOop.inline.hpp"
 32 #include "runtime/frame.hpp"
 33 #include "runtime/registerMap.hpp"
 34 
 35 #ifdef ASSERT
 36 bool stackChunkOopDesc::verify(size_t* out_size, int* out_oops, int* out_frames, int* out_interpreted_frames) {
 37   return InstanceStackChunkKlass::verify(this, out_size, out_oops, out_frames, out_interpreted_frames);
 38 }
 39 #endif
 40 
 41 bool stackChunkOopDesc::should_fix() const {
 42   const bool concurrent_gc = (UseZGC || UseShenandoahGC);
 43   return
 44     UseCompressedOops
 45       ? (concurrent_gc ? should_fix<narrowOop, true>()
 46                        : should_fix<narrowOop, false>())
 47       : (concurrent_gc ? should_fix<oop,       true>()
 48                        : should_fix<oop,       false>());
 49 }
 50 
 51 frame stackChunkOopDesc::top_frame(RegisterMap* map) {
 52   // tty->print_cr(">>> stackChunkOopDesc::top_frame this: %p map: %p map->chunk: %p", this, map, (stackChunkOopDesc*)map->stack_chunk()());
 53   StackChunkFrameStream<true> fs(this);
 54 
 55   map->set_stack_chunk(this);
 56   fs.initialize_register_map(map);
 57   // if (map->update_map() && should_fix()) InstanceStackChunkKlass::fix_frame<true, false>(fs, map);
 58 
 59   frame f = fs.to_frame();
 60   relativize_frame(f);
 61   f.set_frame_index(0);
 62   return f;
 63 }
 64 
 65 frame stackChunkOopDesc::sender(const frame& f, RegisterMap* map) {
 66   // tty->print_cr(">>> stackChunkOopDesc::sender this: %p map: %p map->chunk: %p", this, map, (stackChunkOopDesc*)map->stack_chunk()()); derelativize(f).print_on<true>(tty);
 67   assert (map->in_cont(), "");
 68   assert (!map->include_argument_oops(), "");
 69   assert (!f.is_empty(), "");
 70   assert (map->stack_chunk() == this, "");
 71   assert (this != nullptr, "");
 72   assert (!is_empty(), "");
 73 
 74   int index = f.frame_index();
 75   StackChunkFrameStream<true> fs(this, derelativize(f));
 76   fs.next(map);
 77 
 78   if (!fs.is_done()) {
 79     frame sender = fs.to_frame();
 80     assert (is_usable_in_chunk(sender.unextended_sp()), "");
 81     relativize_frame(sender);
 82 
 83     sender.set_frame_index(index+1);
 84     return sender;
 85   }
 86 
 87   if (parent() != (oop)nullptr) {
 88     assert (!parent()->is_empty(), "");
 89     return parent()->top_frame(map);
 90   }
 91 
 92   return Continuation::continuation_parent_frame(map);
 93 }
 94 
 95 static int num_java_frames(CompiledMethod* cm, address pc) {
 96   int count = 0;
 97   for (ScopeDesc* scope = cm->scope_desc_at(pc); scope != nullptr; scope = scope->sender())
 98     count++;
 99   return count;
100 }
101 
102 static int num_java_frames(const StackChunkFrameStream<true>& f) {
103   assert (f.is_interpreted() || (f.cb() != nullptr && f.cb()->is_compiled() && f.cb()->as_compiled_method()->is_java_method()), "");
104   return f.is_interpreted() ? 1 : num_java_frames(f.cb()->as_compiled_method(), f.orig_pc());
105 }
106 
107 int stackChunkOopDesc::num_java_frames() const {
108   int n = 0;
109   for (StackChunkFrameStream<true> f(const_cast<stackChunkOopDesc*>(this)); !f.is_done(); f.next(SmallRegisterMap::instance)) {
110     if (!f.is_stub()) n += ::num_java_frames(f);
111   }
112   return n;
113 }
114 
115 void stackChunkOopDesc::print_on(bool verbose, outputStream* st) const {
116   if (this == nullptr) {
117     st->print_cr("NULL");
118   } else if (*((juint*)this) == badHeapWordVal) {
119     st->print("BAD WORD");
120   } else if (*((juint*)this) == badMetaWordVal) {
121     st->print("BAD META WORD");
122   } else {
123     InstanceStackChunkKlass::print_chunk(const_cast<stackChunkOopDesc*>(this), verbose, st);
124   }
125 }
126