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 #ifndef SHARE_VM_COMPILER_OOPMAP_INLINE_HPP
  26 #define SHARE_VM_COMPILER_OOPMAP_INLINE_HPP
  27 
  28 #include "gc/shared/collectedHeap.hpp"
  29 #include "memory/universe.hpp"
  30 #include "oops/compressedOops.hpp"
  31 
  32 inline const ImmutableOopMap* ImmutableOopMapSet::find_map_at_slot(int slot, int pc_offset) const {
  33   assert(slot >= 0 && slot < _count, "bounds count: %d slot: %d", _count, slot);
  34   ImmutableOopMapPair* pairs = get_pairs();
  35   ImmutableOopMapPair* last = &pairs[slot];
  36   assert(last->pc_offset() == pc_offset, "oopmap not found");
  37   return last->get_from(this);
  38 }
  39 
  40 inline const ImmutableOopMap* ImmutableOopMapPair::get_from(const ImmutableOopMapSet* set) const {
  41   return set->oopmap_at_offset(_oopmap_offset);
  42 }
  43 
  44 inline bool SkipNullValue::should_skip(oop val) {
  45   return val == (oop)NULL || CompressedOops::is_base(val);
  46 }
  47 
  48 template <typename OopFnT, typename DerivedOopFnT, typename ValueFilterT>
  49 template <typename OopMapStreamT, typename RegisterMapT>
  50 void OopMapDo<OopFnT, DerivedOopFnT, ValueFilterT>::iterate_oops_do(const frame *fr, const RegisterMapT *reg_map, const ImmutableOopMap* oopmap) {
  51   NOT_PRODUCT(if (TraceCodeBlobStacks) OopMapSet::trace_codeblob_maps(fr, reg_map->as_RegisterMap());)
  52 
  53   // handle derived pointers first (otherwise base pointer may be
  54   // changed before derived pointer offset has been collected)
  55   if (reg_map->validate_oops())
  56     walk_derived_pointers<OopMapStreamT>(fr, oopmap, reg_map);
  57 
  58   OopMapValue omv;
  59   // We want coop and oop oop_types
  60   int mask = OopMapValue::oop_value | OopMapValue::narrowoop_value;
  61   {
  62     for (OopMapStreamT oms(oopmap,mask); !oms.is_done(); oms.next()) {
  63       omv = oms.current();
  64       oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map);
  65       // It should be an error if no location can be found for a
  66       // register mentioned as contained an oop of some kind.  Maybe
  67       // this was allowed previously because value_value items might
  68       // be missing?
  69 #ifdef ASSERT
  70     if (loc == NULL) {
  71       if (reg_map->should_skip_missing())
  72         continue;
  73       VMReg reg = omv.reg();
  74       tty->print_cr("missing saved register: reg: " INTPTR_FORMAT " %s loc: %p", reg->value(), reg->name(), loc);
  75       fr->print_on(tty);
  76     }
  77 #endif
  78       guarantee(loc != NULL, "missing saved register");
  79       if ( omv.type() == OopMapValue::oop_value ) {
  80         oop val = *loc;
  81         if (ValueFilterT::should_skip(val)) { // TODO: UGLY (basically used to decide if we're freezing/thawing continuation)
  82           // Ignore NULL oops and decoded NULL narrow oops which
  83           // equal to CompressedOops::base() when a narrow oop
  84           // implicit null check is used in compiled code.
  85           // The narrow_oop_base could be NULL or be the address
  86           // of the page below heap depending on compressed oops mode.
  87           continue;
  88         }
  89 #ifdef ASSERT
  90         // We can not verify the oop here if we are using ZGC, the oop
  91         // will be bad in case we had a safepoint between a load and a
  92         // load barrier.
  93         if (!UseZGC && reg_map->validate_oops() &&
  94             ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) ||
  95              !Universe::heap()->is_in_or_null(*loc))) {
  96           tty->print_cr("# Found non oop pointer.  Dumping state at failure");
  97           // try to dump out some helpful debugging information
  98           OopMapSet::trace_codeblob_maps(fr, reg_map->as_RegisterMap());
  99           omv.print();
 100           tty->print_cr("register r");
 101           omv.reg()->print();
 102           tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc);
 103           // os::print_location(tty, (intptr_t)*loc);
 104           tty->print("pc: "); os::print_location(tty, (intptr_t)fr->pc());
 105           fr->print_value_on(tty, NULL);
 106           // do the real assert.
 107           assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer");
 108         }
 109 #endif // ASSERT
 110         _oop_fn->do_oop(loc);
 111       } else if ( omv.type() == OopMapValue::narrowoop_value ) {
 112         narrowOop *nl = (narrowOop*)loc;
 113 #ifndef VM_LITTLE_ENDIAN
 114         VMReg vmReg = omv.reg();
 115         // Don't do this on SPARC float registers as they can be individually addressed
 116         if (!vmReg->is_stack() SPARC_ONLY(&& !vmReg->is_FloatRegister())) {
 117           // compressed oops in registers only take up 4 bytes of an
 118           // 8 byte register but they are in the wrong part of the
 119           // word so adjust loc to point at the right place.
 120           nl = (narrowOop*)((address)nl + 4);
 121         }
 122 #endif
 123         _oop_fn->do_oop(nl);
 124       }
 125     }
 126   }
 127 
 128   // When thawing continuation frames, we want to walk derived pointers
 129   // after walking oops
 130   if (!reg_map->validate_oops())
 131     walk_derived_pointers<OopMapStreamT>(fr, oopmap, reg_map);
 132 }
 133 
 134 template <typename OopMapFnT, typename DerivedOopFnT, typename ValueFilterT>
 135 template <typename OopMapStreamT, typename RegisterMapT>
 136 void OopMapDo<OopMapFnT, DerivedOopFnT, ValueFilterT>::walk_derived_pointers(const frame *fr, const ImmutableOopMap* map, const RegisterMapT *reg_map) {
 137   OopMapStreamT oms(map,OopMapValue::derived_oop_value);
 138   if (!oms.is_done()) {
 139 #ifndef TIERED
 140     COMPILER1_PRESENT(ShouldNotReachHere();)
 141 #if INCLUDE_JVMCI
 142     if (UseJVMCICompiler) {
 143       ShouldNotReachHere();
 144     }
 145 #endif
 146 #endif // !TIERED
 147 
 148     walk_derived_pointers1<OopMapStreamT>(oms, fr, reg_map);
 149   }
 150 }
 151 
 152 template <typename OopMapFnT, typename DerivedOopFnT, typename ValueFilterT>
 153 template <typename OopMapStreamT, typename RegisterMapT>
 154 void OopMapDo<OopMapFnT, DerivedOopFnT, ValueFilterT>::walk_derived_pointers1(OopMapStreamT& oms, const frame *fr, const RegisterMapT *reg_map) {
 155   assert (fr != NULL, "");
 156   assert (_derived_oop_fn != NULL, "");
 157   OopMapValue omv;
 158   do {
 159     omv = oms.current();
 160     oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map);
 161 
 162     DEBUG_ONLY(if (reg_map->should_skip_missing()) continue;)
 163     guarantee(loc != NULL, "missing saved register");
 164     oop *derived_loc = loc;
 165     oop *base_loc    = fr->oopmapreg_to_location(omv.content_reg(), reg_map);
 166     // Ignore NULL oops and decoded NULL narrow oops which
 167     // equal to CompressedOops::base() when a narrow oop
 168     // implicit null check is used in compiled code.
 169     // The narrow_oop_base could be NULL or be the address
 170     // of the page below heap depending on compressed oops mode.
 171     if (base_loc != NULL && *base_loc != (oop)NULL && !CompressedOops::is_base(*base_loc)) {
 172       _derived_oop_fn->do_derived_oop(base_loc, derived_loc);
 173     }
 174     oms.next();
 175   } while (!oms.is_done());
 176 }
 177 
 178 
 179 template <typename OopFnT, typename DerivedOopFnT, typename ValueFilterT>
 180 template <typename RegisterMapT>
 181 void OopMapDo<OopFnT, DerivedOopFnT, ValueFilterT>::oops_do(const frame *fr, const RegisterMapT *reg_map, const ImmutableOopMap* oopmap) {
 182   if (oopmap->_exploded != NULL) {
 183     iterate_oops_do<ExplodedOopMapStream>(fr, reg_map, oopmap);
 184   } else {
 185     iterate_oops_do<OopMapStream>(fr, reg_map, oopmap);
 186   }
 187 }
 188 
 189 #endif
 190