Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/PageCache.java
41161 views
1
/*
2
* Copyright (c) 2000, 2002, 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
package sun.jvm.hotspot.debugger;
26
27
/** This class implements an LRU page-level cache of configurable page
28
size and number of pages. It is configured with a PageFetcher
29
which enables it to transparently satisfy requests which span
30
multiple pages when one or more of those pages is not in the
31
cache. It is generic enough to be sharable among debugger
32
implementations. */
33
34
import sun.jvm.hotspot.utilities.*;
35
36
public class PageCache {
37
/** The pageSize must be a power of two and implicitly specifies the
38
alignment of pages. numPages specifies how many pages should be
39
cached. */
40
public PageCache(long pageSize,
41
long maxNumPages,
42
PageFetcher fetcher) {
43
checkPageInfo(pageSize, maxNumPages);
44
this.pageSize = pageSize;
45
this.maxNumPages = maxNumPages;
46
this.fetcher = fetcher;
47
addressToPageMap = new LongHashMap();
48
enabled = true;
49
}
50
51
/** This handles fetches which span multiple pages by virtue of the
52
presence of the PageFetcher. Throws UnmappedAddressException if
53
a page on which data was requested was unmapped. This can not
54
really handle numBytes > 32 bits. */
55
public synchronized byte[] getData(long startAddress, long numBytes)
56
throws UnmappedAddressException {
57
byte[] data = new byte[(int) numBytes];
58
long numRead = 0;
59
60
while (numBytes > 0) {
61
long pageBaseAddress = startAddress & pageMask;
62
// Look up this page
63
Page page = checkPage(getPage(pageBaseAddress), startAddress);
64
// Figure out how many bytes to read from this page
65
long pageOffset = startAddress - pageBaseAddress;
66
long numBytesFromPage = Math.min(pageSize - pageOffset, numBytes);
67
// Read them starting at the appropriate offset in the
68
// destination buffer
69
page.getDataAsBytes(startAddress, numBytesFromPage, data, numRead);
70
// Increment offsets
71
numRead += numBytesFromPage;
72
numBytes -= numBytesFromPage;
73
startAddress += numBytesFromPage;
74
}
75
76
return data;
77
}
78
79
public synchronized boolean getBoolean(long address) {
80
return (getByte(address) != 0);
81
}
82
83
public synchronized byte getByte(long address) {
84
return checkPage(getPage(address & pageMask), address).getByte(address);
85
}
86
87
public synchronized short getShort(long address, boolean bigEndian) {
88
return checkPage(getPage(address & pageMask), address).getShort(address, bigEndian);
89
}
90
91
public synchronized char getChar(long address, boolean bigEndian) {
92
return checkPage(getPage(address & pageMask), address).getChar(address, bigEndian);
93
}
94
95
public synchronized int getInt(long address, boolean bigEndian) {
96
return checkPage(getPage(address & pageMask), address).getInt(address, bigEndian);
97
}
98
99
public synchronized long getLong(long address, boolean bigEndian) {
100
return checkPage(getPage(address & pageMask), address).getLong(address, bigEndian);
101
}
102
103
public synchronized float getFloat(long address, boolean bigEndian) {
104
return checkPage(getPage(address & pageMask), address).getFloat(address, bigEndian);
105
}
106
107
public synchronized double getDouble(long address, boolean bigEndian) {
108
return checkPage(getPage(address & pageMask), address).getDouble(address, bigEndian);
109
}
110
111
/** A mechanism for clearing cached data covering the given region */
112
public synchronized void clear(long startAddress, long numBytes) {
113
long pageBaseAddress = startAddress & pageMask;
114
long endAddress = startAddress + numBytes;
115
while (pageBaseAddress < endAddress) {
116
flushPage(pageBaseAddress);
117
pageBaseAddress += pageSize;
118
}
119
}
120
121
/** A mechanism for clearing out the cache is necessary to handle
122
detaching and reattaching */
123
public synchronized void clear() {
124
// Should probably break next/prev links in list as well
125
addressToPageMap.clear();
126
lruList = null;
127
numPages = 0;
128
}
129
130
/** Disables the page cache; no further pages will be added to the
131
cache and all existing pages will be flushed. Call this when the
132
target process has been resumed. */
133
public synchronized void disable() {
134
enabled = false;
135
clear();
136
}
137
138
/** Enables the page cache; fetched pages will be added to the
139
cache. Call this when the target process has been suspended. */
140
public synchronized void enable() {
141
enabled = true;
142
}
143
144
145
//--------------------------------------------------------------------------------
146
// Internals only below this point
147
//
148
149
// This is implemented with two data structures: a hash table for
150
// fast lookup by a page's base address and a circular doubly-linked
151
// list for implementing LRU behavior.
152
153
private boolean enabled;
154
private long pageSize;
155
private long maxNumPages;
156
private long pageMask;
157
private long numPages;
158
private PageFetcher fetcher;
159
private LongHashMap addressToPageMap; // Map<long, Page>
160
private Page lruList; // Most recently fetched page, or null
161
162
/** Page fetcher plus LRU functionality */
163
private Page getPage(long pageBaseAddress) {
164
// Check head of LRU list first to avoid hash table lookup and
165
// extra list work if possible
166
if (lruList != null) {
167
if (lruList.getBaseAddress() == pageBaseAddress) {
168
// Hit. Return it.
169
return lruList;
170
}
171
}
172
// Long key = new Long(pageBaseAddress);
173
long key = pageBaseAddress;
174
Page page = (Page) addressToPageMap.get(key);
175
if (page == null) {
176
// System.err.println("** Cache miss at address 0x" + Long.toHexString(pageBaseAddress) + " **");
177
// Fetch new page
178
page = fetcher.fetchPage(pageBaseAddress, pageSize);
179
if (enabled) {
180
// Add to cache, evicting last element if necessary
181
addressToPageMap.put(key, page);
182
if (Assert.ASSERTS_ENABLED) {
183
Assert.that(page == (Page) addressToPageMap.get(pageBaseAddress),
184
"must have found page in cache!");
185
}
186
addPageToList(page);
187
// See whether eviction of oldest is necessary
188
if (numPages == maxNumPages) {
189
Page evictedPage = lruList.getPrev();
190
// System.err.println("-> Evicting page at 0x" + Long.toHexString(evictedPage.getBaseAddress()) +
191
// "; " + countPages() + " pages left (expect " + numPages + ")");
192
removePageFromList(evictedPage);
193
addressToPageMap.remove(evictedPage.getBaseAddress());
194
} else {
195
++numPages;
196
}
197
}
198
} else {
199
// Page already in cache, move to front of list
200
removePageFromList(page);
201
addPageToList(page);
202
}
203
return page;
204
}
205
206
private Page checkPage(Page page, long startAddress) {
207
if (!page.isMapped()) {
208
throw new UnmappedAddressException(startAddress);
209
}
210
return page;
211
}
212
213
private int countPages() {
214
Page page = lruList;
215
int num = 0;
216
if (page == null) {
217
return num;
218
}
219
do {
220
++num;
221
page = page.getNext();
222
} while (page != lruList);
223
return num;
224
}
225
226
private void flushPage(long pageBaseAddress) {
227
long key = pageBaseAddress;
228
Page page = (Page) addressToPageMap.remove(key);
229
if (page != null) {
230
removePageFromList(page);
231
}
232
}
233
234
// Adds given page to head of list
235
private void addPageToList(Page page) {
236
if (lruList == null) {
237
lruList = page;
238
page.setNext(page);
239
page.setPrev(page);
240
} else {
241
// Add to front of list
242
page.setNext(lruList);
243
page.setPrev(lruList.getPrev());
244
lruList.getPrev().setNext(page);
245
lruList.setPrev(page);
246
lruList = page;
247
}
248
}
249
250
// Removes given page from list
251
private void removePageFromList(Page page) {
252
if (page.getNext() == page) {
253
lruList = null;
254
} else {
255
if (lruList == page) {
256
lruList = page.getNext();
257
}
258
page.getPrev().setNext(page.getNext());
259
page.getNext().setPrev(page.getPrev());
260
}
261
page.setPrev(null);
262
page.setNext(null);
263
}
264
265
/** Ensure that page size fits within 32 bits and is a power of two, and that maxNumPages > 0 */
266
private void checkPageInfo(long pageSize, long maxNumPages) {
267
if ((pageSize <= 0) || maxNumPages <= 0) {
268
throw new IllegalArgumentException("pageSize and maxNumPages must both be greater than zero");
269
}
270
long tmpPageSize = pageSize >>> 32;
271
if (tmpPageSize != 0) {
272
throw new IllegalArgumentException("pageSize " + pageSize + " too big (must fit within 32 bits)");
273
}
274
int numNonZeroBits = 0;
275
for (int i = 0; i < 32; ++i) {
276
if ((pageSize & 1L) != 0) {
277
++numNonZeroBits;
278
if ((numNonZeroBits > 1) || (i == 0)) {
279
throw new IllegalArgumentException("pageSize " + pageSize + " must be a power of two");
280
}
281
}
282
pageSize >>>= 1;
283
if (numNonZeroBits == 0) {
284
pageMask = (pageMask << 1) | 1L;
285
}
286
}
287
pageMask = ~pageMask;
288
}
289
}
290
291