src/hotspot/share/jvmci/metadataHandleBlock.hpp
changeset 54669 ad45b3802d4e
equal deleted inserted replaced
54668:0bda2308eded 54669:ad45b3802d4e
       
     1 /*
       
     2  * Copyright (c) 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 #ifndef SHARE_JVMCI_METADATAHANDLEBLOCK_HPP
       
    25 #define SHARE_JVMCI_METADATAHANDLEBLOCK_HPP
       
    26 
       
    27 #include "oops/constantPool.hpp"
       
    28 #include "oops/metadata.hpp"
       
    29 #include "oops/method.hpp"
       
    30 #include "runtime/handles.hpp"
       
    31 #include "runtime/os.hpp"
       
    32 
       
    33 #ifdef ASSERT
       
    34 #define METADATA_TRACK_NAMES
       
    35 #endif
       
    36 
       
    37 struct _jmetadata {
       
    38  private:
       
    39   Metadata* _value;
       
    40 #ifdef METADATA_TRACK_NAMES
       
    41   // Debug data for tracking stale metadata
       
    42   const char* _name;
       
    43 #endif
       
    44 
       
    45  public:
       
    46   Metadata* value() { return _value; }
       
    47 
       
    48 #ifdef METADATA_TRACK_NAMES
       
    49   void initialize() {
       
    50     _value = NULL;
       
    51     _name = NULL;
       
    52   }
       
    53 #endif
       
    54 
       
    55   void set_value(Metadata* value) {
       
    56     _value = value;
       
    57   }
       
    58 
       
    59 #ifdef METADATA_TRACK_NAMES
       
    60   const char* name() { return _name; }
       
    61   void set_name(const char* name) {
       
    62     if (_name != NULL) {
       
    63       os::free((void*) _name);
       
    64       _name = NULL;
       
    65     }
       
    66     if (name != NULL) {
       
    67       _name = os::strdup(name);
       
    68     }
       
    69   }
       
    70 #endif
       
    71 };
       
    72 
       
    73 typedef struct _jmetadata HandleRecord;
       
    74 typedef struct _jmetadata *jmetadata;
       
    75 
       
    76 // JVMCI maintains direct references to metadata. To make these references safe in the face of
       
    77 // class redefinition, they are held in handles so they can be scanned during GC. They are
       
    78 // managed in a cooperative way between the Java code and HotSpot. A handle is filled in and
       
    79 // passed back to the Java code which is responsible for setting the handle to NULL when it
       
    80 // is no longer in use. This is done by jdk.vm.ci.hotspot.HandleCleaner. The
       
    81 // rebuild_free_list function notices when the handle is clear and reclaims it for re-use.
       
    82 class MetadataHandleBlock : public CHeapObj<mtJVMCI> {
       
    83  private:
       
    84   enum SomeConstants {
       
    85     block_size_in_handles  = 32,      // Number of handles per handle block
       
    86     ptr_tag = 1,
       
    87     ptr_mask = ~((intptr_t)ptr_tag)
       
    88   };
       
    89 
       
    90 
       
    91   // Free handles always have their low bit set so those pointers can
       
    92   // be distinguished from handles which are in use.  The last handle
       
    93   // on the free list has a NULL pointer with the tag bit set, so it's
       
    94   // clear that the handle has been reclaimed.  The _free_list is
       
    95   // always a real pointer to a handle.
       
    96 
       
    97   HandleRecord    _handles[block_size_in_handles]; // The handles
       
    98   int             _top;                         // Index of next unused handle
       
    99   MetadataHandleBlock* _next;                   // Link to next block
       
   100 
       
   101   // The following instance variables are only used by the first block in a chain.
       
   102   // Having two types of blocks complicates the code and the space overhead is negligible.
       
   103   static MetadataHandleBlock* _last;                   // Last block in use
       
   104   static intptr_t        _free_list;                   // Handle free list
       
   105   static int             _allocate_before_rebuild;     // Number of blocks to allocate before rebuilding free list
       
   106 
       
   107   MetadataHandleBlock() {
       
   108     _top = 0;
       
   109     _next = NULL;
       
   110 #ifdef METADATA_TRACK_NAMES
       
   111     for (int i = 0; i < block_size_in_handles; i++) {
       
   112       _handles[i].initialize();
       
   113     }
       
   114 #endif
       
   115   }
       
   116 
       
   117   const char* get_name(int index) {
       
   118 #ifdef METADATA_TRACK_NAMES
       
   119     return _handles[index].name();
       
   120 #else
       
   121     return "<missing>";
       
   122 #endif
       
   123   }
       
   124 
       
   125   static HandleRecord* get_free_handle() {
       
   126     assert(_free_list != 0, "should check before calling");
       
   127     HandleRecord* handle = (HandleRecord*) (_free_list & ptr_mask);
       
   128     _free_list = (ptr_mask & (intptr_t) (handle->value()));
       
   129     assert(_free_list != ptr_tag, "should be null");
       
   130     handle->set_value(NULL);
       
   131     return handle;
       
   132   }
       
   133 
       
   134   static HandleRecord* get_handle() {
       
   135     assert(_last != NULL, "sanity");
       
   136     // Try last block
       
   137     if (_last->_top < block_size_in_handles) {
       
   138       return &(_last->_handles)[_last->_top++];
       
   139     } else if (_free_list != 0) {
       
   140       // Try free list
       
   141       return get_free_handle();
       
   142     }
       
   143     return NULL;
       
   144   }
       
   145 
       
   146   void rebuild_free_list();
       
   147 
       
   148   jmetadata allocate_metadata_handle(Metadata* metadata);
       
   149 
       
   150  public:
       
   151   jmetadata allocate_handle(const methodHandle& handle)       { return allocate_metadata_handle(handle()); }
       
   152   jmetadata allocate_handle(const constantPoolHandle& handle) { return allocate_metadata_handle(handle()); }
       
   153 
       
   154   static MetadataHandleBlock* allocate_block() { return new MetadataHandleBlock(); }
       
   155 
       
   156   // Adds `handle` to the free list in this block
       
   157   static void chain_free_list(HandleRecord* handle) {
       
   158     handle->set_value((Metadata*) (ptr_tag | _free_list));
       
   159 #ifdef METADATA_TRACK_NAMES
       
   160     handle->set_name(NULL);
       
   161 #endif
       
   162     _free_list = (intptr_t) handle;
       
   163   }
       
   164 
       
   165   void metadata_do(void f(Metadata*));
       
   166 
       
   167   void do_unloading();
       
   168 };
       
   169 
       
   170 #endif // SHARE_JVMCI_METADATAHANDLEBLOCK_HPP