-
Notifications
You must be signed in to change notification settings - Fork 5.8k
/
Copy pathoopMapCache.hpp
191 lines (154 loc) · 7.47 KB
/
oopMapCache.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_INTERPRETER_OOPMAPCACHE_HPP
#define SHARE_INTERPRETER_OOPMAPCACHE_HPP
#include "runtime/handles.hpp"
#include "runtime/mutex.hpp"
#include "utilities/globalDefinitions.hpp"
// A Cache for storing (method, bci) -> oopMap.
// The memory management system uses the cache when locating object
// references in an interpreted frame.
//
// OopMapCache's are allocated lazily per InstanceKlass.
// The oopMap (InterpreterOopMap) is stored as a bit mask. If the
// bit_mask can fit into four words it is stored in
// the _bit_mask array, otherwise it is allocated on the heap.
// For OopMapCacheEntry the bit_mask is allocated in the C heap
// because these entries persist between garbage collections.
// For InterpreterOopMap the bit_mask is allocated in the C heap
// to avoid issues with allocations from the resource area that have
// to live accross the oop closure. InterpreterOopMap should only be
// created and deleted during the same garbage collection.
//
// If ENABBLE_ZAP_DEAD_LOCALS is defined, two bits are used
// per entry instead of one. In all cases,
// the first bit is set to indicate oops as opposed to other
// values. If the second bit is available,
// it is set for dead values. We get the following encoding:
//
// 00 live value
// 01 live oop
// 10 dead value
// 11 <unused> (we cannot distinguish between dead oops or values with the current oop map generator)
class OffsetClosure {
public:
virtual void offset_do(int offset) = 0;
};
class Method;
class OopMapCacheEntry;
class InterpreterOopMap: ResourceObj {
friend class OopMapCache;
public:
enum {
N = 4, // the number of words reserved
// for inlined mask storage
small_mask_limit = N * BitsPerWord, // the maximum number of bits
// available for small masks,
// small_mask_limit can be set to 0
// for testing bit_mask allocation
bits_per_entry = 2,
dead_bit_number = 1,
oop_bit_number = 0
};
private:
Method* _method; // the method for which the mask is valid
int _mask_size; // the mask size in bits (USHRT_MAX if invalid)
int _expression_stack_size; // the size of the expression stack in slots
unsigned short _bci; // the bci for which the mask is valid
protected:
int _num_oops;
intptr_t _bit_mask[N]; // the bit mask if
// mask_size <= small_mask_limit,
// ptr to bit mask otherwise
// "protected" so that sub classes can
// access it without using trickery in
// method bit_mask().
// access methods
Method* method() const { return _method; }
void set_method(Method* v) { _method = v; }
unsigned short bci() const { return _bci; }
void set_bci(unsigned short v) { _bci = v; }
int mask_size() const { return _mask_size; }
void set_mask_size(int v) { _mask_size = v; }
// Test bit mask size and return either the in-line bit mask or allocated
// bit mask.
uintptr_t* bit_mask() const { return (uintptr_t*)(mask_size() <= small_mask_limit ? (intptr_t)_bit_mask : _bit_mask[0]); }
// return the word size of_bit_mask. mask_size() <= 4 * MAX_USHORT
size_t mask_word_size() const {
return (mask_size() + BitsPerWord - 1) / BitsPerWord;
}
uintptr_t entry_at(int offset) const { int i = offset * bits_per_entry; return bit_mask()[i / BitsPerWord] >> (i % BitsPerWord); }
void set_expression_stack_size(int sz) { _expression_stack_size = sz; }
// Lookup
bool match(const methodHandle& method, int bci) const { return _method == method() && _bci == bci; }
bool is_empty() const;
// Initialization
void initialize();
public:
InterpreterOopMap();
~InterpreterOopMap();
// Copy the OopMapCacheEntry in parameter "src" into this
// InterpreterOopMap. If the _bit_mask[0] in "src" points to
// allocated space (i.e., the bit mask was too large to hold
// in-line), allocate the space from the C heap.
void copy_from(const OopMapCacheEntry* src);
void iterate_oop(OffsetClosure* oop_closure) const;
void print() const;
int number_of_entries() const { return mask_size() / bits_per_entry; }
bool is_dead(int offset) const { return (entry_at(offset) & (1 << dead_bit_number)) != 0; }
bool is_oop (int offset) const { return (entry_at(offset) & (1 << oop_bit_number )) != 0; }
int num_oops() const { return _num_oops; }
int expression_stack_size() const { return _expression_stack_size; }
// Determines if a valid mask has been computed
bool has_valid_mask() const { return _mask_size != USHRT_MAX; }
};
class OopMapCache : public CHeapObj<mtClass> {
static OopMapCacheEntry* volatile _old_entries;
private:
static constexpr int size = 32; // Use fixed size for now
static constexpr int probe_depth = 3; // probe depth in case of collisions
OopMapCacheEntry* volatile _array[size];
unsigned int hash_value_for(const methodHandle& method, int bci) const;
OopMapCacheEntry* entry_at(int i) const;
bool put_at(int i, OopMapCacheEntry* entry, OopMapCacheEntry* old);
static void enqueue_for_cleanup(OopMapCacheEntry* entry);
void flush();
public:
OopMapCache();
~OopMapCache(); // free up memory
// flush cache entry is occupied by an obsolete method
void flush_obsolete_entries();
// Returns the oopMap for (method, bci) in parameter "entry".
// Returns false if an oop map was not found.
void lookup(const methodHandle& method, int bci, InterpreterOopMap* entry);
// Compute an oop map without updating the cache or grabbing any locks (for debugging)
static void compute_one_oop_map(const methodHandle& method, int bci, InterpreterOopMap* entry);
// Check if we need to clean up old entries
static bool has_cleanup_work();
// Request cleanup if work is needed and notification is currently possible
static void try_trigger_cleanup();
// Clean up the old entries
static void cleanup();
};
#endif // SHARE_INTERPRETER_OOPMAPCACHE_HPP