src/hotspot/share/gc/shared/oopStorageParState.inline.hpp
changeset 48816 3495d6050efe
child 49005 cc2b457f2589
equal deleted inserted replaced
48815:d80d521e9cb1 48816:3495d6050efe
       
     1 /*
       
     2  * Copyright (c) 2018, 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_GC_SHARED_OOPSTORAGEPARSTATE_INLINE_HPP
       
    26 #define SHARE_GC_SHARED_OOPSTORAGEPARSTATE_INLINE_HPP
       
    27 
       
    28 #include "gc/shared/oopStorage.inline.hpp"
       
    29 #include "memory/allocation.hpp"
       
    30 #include "metaprogramming/conditional.hpp"
       
    31 #include "utilities/macros.hpp"
       
    32 
       
    33 #if INCLUDE_ALL_GCS
       
    34 
       
    35 //////////////////////////////////////////////////////////////////////////////
       
    36 // Support for parallel and optionally concurrent state iteration.
       
    37 //
       
    38 // Parallel iteration is for the exclusive use of the GC.  Other iteration
       
    39 // clients must use serial iteration.
       
    40 //
       
    41 // Concurrent Iteration
       
    42 //
       
    43 // Iteration involves the _active_list, which contains all of the blocks owned
       
    44 // by a storage object.  This is a doubly-linked list, linked through
       
    45 // dedicated fields in the blocks.
       
    46 //
       
    47 // At most one concurrent ParState can exist at a time for a given storage
       
    48 // object.
       
    49 //
       
    50 // A concurrent ParState sets the associated storage's
       
    51 // _concurrent_iteration_active flag true when the state is constructed, and
       
    52 // sets it false when the state is destroyed.  These assignments are made with
       
    53 // _active_mutex locked.  Meanwhile, empty block deletion is not done while
       
    54 // _concurrent_iteration_active is true.  The flag check and the dependent
       
    55 // removal of a block from the _active_list is performed with _active_mutex
       
    56 // locked.  This prevents concurrent iteration and empty block deletion from
       
    57 // interfering with with each other.
       
    58 //
       
    59 // Both allocate() and delete_empty_blocks_concurrent() lock the
       
    60 // _allocate_mutex while performing their respective list manipulations,
       
    61 // preventing them from interfering with each other.
       
    62 //
       
    63 // When allocate() creates a new block, it is added to the front of the
       
    64 // _active_list.  Then _active_head is set to the new block.  When concurrent
       
    65 // iteration is started (by a parallel worker thread calling the state's
       
    66 // iterate() function), the current _active_head is used as the initial block
       
    67 // for the iteration, with iteration proceeding down the list headed by that
       
    68 // block.
       
    69 //
       
    70 // As a result, the list over which concurrent iteration operates is stable.
       
    71 // However, once the iteration is started, later allocations may add blocks to
       
    72 // the front of the list that won't be examined by the iteration.  And while
       
    73 // the list is stable, concurrent allocate() and release() operations may
       
    74 // change the set of allocated entries in a block at any time during the
       
    75 // iteration.
       
    76 //
       
    77 // As a result, a concurrent iteration handler must accept that some
       
    78 // allocations and releases that occur after the iteration started will not be
       
    79 // seen by the iteration.  Further, some may overlap examination by the
       
    80 // iteration.  To help with this, allocate() and release() have an invariant
       
    81 // that an entry's value must be NULL when it is not in use.
       
    82 //
       
    83 // An in-progress delete_empty_blocks_concurrent() operation can contend with
       
    84 // the start of a concurrent iteration over the _active_mutex.  Since both are
       
    85 // under GC control, that potential contention can be eliminated by never
       
    86 // scheduling both operations to run at the same time.
       
    87 //
       
    88 // ParState<concurrent, is_const>
       
    89 //   concurrent must be true if iteration is concurrent with the
       
    90 //   mutator, false if iteration is at a safepoint.
       
    91 //
       
    92 //   is_const must be true if the iteration is over a constant storage
       
    93 //   object, false if the iteration may modify the storage object.
       
    94 //
       
    95 // ParState([const] OopStorage* storage)
       
    96 //   Construct an object for managing an iteration over storage.  For a
       
    97 //   concurrent ParState, empty block deletion for the associated storage
       
    98 //   is inhibited for the life of the ParState.  There can be no more
       
    99 //   than one live concurrent ParState at a time for a given storage object.
       
   100 //
       
   101 // template<typename F> void iterate(F f)
       
   102 //   Repeatedly claims a block from the associated storage that has
       
   103 //   not been processed by this iteration (possibly by other threads),
       
   104 //   and applies f to each entry in the claimed block. Assume p is of
       
   105 //   type const oop* or oop*, according to is_const. Then f(p) must be
       
   106 //   a valid expression whose value is ignored.  Concurrent uses must
       
   107 //   be prepared for an entry's value to change at any time, due to
       
   108 //   mutator activity.
       
   109 //
       
   110 // template<typename Closure> void oops_do(Closure* cl)
       
   111 //   Wrapper around iterate, providing an adaptation layer allowing
       
   112 //   the use of OopClosures and similar objects for iteration.  Assume
       
   113 //   p is of type const oop* or oop*, according to is_const.  Then
       
   114 //   cl->do_oop(p) must be a valid expression whose value is ignored.
       
   115 //   Concurrent uses must be prepared for the entry's value to change
       
   116 //   at any time, due to mutator activity.
       
   117 //
       
   118 // Optional operations, provided only if !concurrent && !is_const.
       
   119 // These are not provided when is_const, because the storage object
       
   120 // may be modified by the iteration infrastructure, even if the
       
   121 // provided closure doesn't modify the storage object.  These are not
       
   122 // provided when concurrent because any pre-filtering behavior by the
       
   123 // iteration infrastructure is inappropriate for concurrent iteration;
       
   124 // modifications of the storage by the mutator could result in the
       
   125 // pre-filtering being applied (successfully or not) to objects that
       
   126 // are unrelated to what the closure finds in the entry.
       
   127 //
       
   128 // template<typename Closure> void weak_oops_do(Closure* cl)
       
   129 // template<typename IsAliveClosure, typename Closure>
       
   130 // void weak_oops_do(IsAliveClosure* is_alive, Closure* cl)
       
   131 //   Wrappers around iterate, providing an adaptation layer allowing
       
   132 //   the use of is-alive closures and OopClosures for iteration.
       
   133 //   Assume p is of type oop*.  Then
       
   134 //
       
   135 //   - cl->do_oop(p) must be a valid expression whose value is ignored.
       
   136 //
       
   137 //   - is_alive->do_object_b(*p) must be a valid expression whose value
       
   138 //   is convertible to bool.
       
   139 //
       
   140 //   If *p == NULL then neither is_alive nor cl will be invoked for p.
       
   141 //   If is_alive->do_object_b(*p) is false, then cl will not be
       
   142 //   invoked on p.
       
   143 
       
   144 class OopStorage::BasicParState VALUE_OBJ_CLASS_SPEC {
       
   145   OopStorage* _storage;
       
   146   void* volatile _next_block;
       
   147   bool _concurrent;
       
   148 
       
   149   // Noncopyable.
       
   150   BasicParState(const BasicParState&);
       
   151   BasicParState& operator=(const BasicParState&);
       
   152 
       
   153   void update_iteration_state(bool value);
       
   154   void ensure_iteration_started();
       
   155   Block* claim_next_block();
       
   156 
       
   157   // Wrapper for iteration handler; ignore handler result and return true.
       
   158   template<typename F> class AlwaysTrueFn;
       
   159 
       
   160 public:
       
   161   BasicParState(OopStorage* storage, bool concurrent);
       
   162   ~BasicParState();
       
   163 
       
   164   template<bool is_const, typename F> void iterate(F f) {
       
   165     // Wrap f in ATF so we can use Block::iterate.
       
   166     AlwaysTrueFn<F> atf_f(f);
       
   167     ensure_iteration_started();
       
   168     typename Conditional<is_const, const Block*, Block*>::type block;
       
   169     while ((block = claim_next_block()) != NULL) {
       
   170       block->iterate(atf_f);
       
   171     }
       
   172   }
       
   173 };
       
   174 
       
   175 template<typename F>
       
   176 class OopStorage::BasicParState::AlwaysTrueFn VALUE_OBJ_CLASS_SPEC {
       
   177   F _f;
       
   178 
       
   179 public:
       
   180   AlwaysTrueFn(F f) : _f(f) {}
       
   181 
       
   182   template<typename OopPtr>     // [const] oop*
       
   183   bool operator()(OopPtr ptr) const { _f(ptr); return true; }
       
   184 };
       
   185 
       
   186 template<bool concurrent, bool is_const>
       
   187 class OopStorage::ParState VALUE_OBJ_CLASS_SPEC {
       
   188   BasicParState _basic_state;
       
   189 
       
   190 public:
       
   191   ParState(const OopStorage* storage) :
       
   192     // For simplicity, always recorded as non-const.
       
   193     _basic_state(const_cast<OopStorage*>(storage), concurrent)
       
   194   {}
       
   195 
       
   196   template<typename F>
       
   197   void iterate(F f) {
       
   198     _basic_state.template iterate<is_const>(f);
       
   199   }
       
   200 
       
   201   template<typename Closure>
       
   202   void oops_do(Closure* cl) {
       
   203     this->iterate(oop_fn(cl));
       
   204   }
       
   205 };
       
   206 
       
   207 template<>
       
   208 class OopStorage::ParState<false, false> VALUE_OBJ_CLASS_SPEC {
       
   209   BasicParState _basic_state;
       
   210 
       
   211 public:
       
   212   ParState(OopStorage* storage) :
       
   213     _basic_state(storage, false)
       
   214   {}
       
   215 
       
   216   template<typename F>
       
   217   void iterate(F f) {
       
   218     _basic_state.template iterate<false>(f);
       
   219   }
       
   220 
       
   221   template<typename Closure>
       
   222   void oops_do(Closure* cl) {
       
   223     this->iterate(oop_fn(cl));
       
   224   }
       
   225 
       
   226   template<typename Closure>
       
   227   void weak_oops_do(Closure* cl) {
       
   228     this->iterate(skip_null_fn(oop_fn(cl)));
       
   229   }
       
   230 
       
   231   template<typename IsAliveClosure, typename Closure>
       
   232   void weak_oops_do(IsAliveClosure* is_alive, Closure* cl) {
       
   233     this->iterate(if_alive_fn(is_alive, oop_fn(cl)));
       
   234   }
       
   235 };
       
   236 
       
   237 #endif // INCLUDE_ALL_GCS
       
   238 
       
   239 #endif // include guard