comparison agent/src/share/classes/sun/jvm/hotspot/debugger/PageCache.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c18cbe5936b8
comparison
equal deleted inserted replaced
-1:000000000000 0:a61af66fc99e
1 /*
2 * Copyright 2000-2002 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any 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 }