Path: blob/master/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/PageCache.java
41161 views
/*1* Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324package sun.jvm.hotspot.debugger;2526/** This class implements an LRU page-level cache of configurable page27size and number of pages. It is configured with a PageFetcher28which enables it to transparently satisfy requests which span29multiple pages when one or more of those pages is not in the30cache. It is generic enough to be sharable among debugger31implementations. */3233import sun.jvm.hotspot.utilities.*;3435public class PageCache {36/** The pageSize must be a power of two and implicitly specifies the37alignment of pages. numPages specifies how many pages should be38cached. */39public PageCache(long pageSize,40long maxNumPages,41PageFetcher fetcher) {42checkPageInfo(pageSize, maxNumPages);43this.pageSize = pageSize;44this.maxNumPages = maxNumPages;45this.fetcher = fetcher;46addressToPageMap = new LongHashMap();47enabled = true;48}4950/** This handles fetches which span multiple pages by virtue of the51presence of the PageFetcher. Throws UnmappedAddressException if52a page on which data was requested was unmapped. This can not53really handle numBytes > 32 bits. */54public synchronized byte[] getData(long startAddress, long numBytes)55throws UnmappedAddressException {56byte[] data = new byte[(int) numBytes];57long numRead = 0;5859while (numBytes > 0) {60long pageBaseAddress = startAddress & pageMask;61// Look up this page62Page page = checkPage(getPage(pageBaseAddress), startAddress);63// Figure out how many bytes to read from this page64long pageOffset = startAddress - pageBaseAddress;65long numBytesFromPage = Math.min(pageSize - pageOffset, numBytes);66// Read them starting at the appropriate offset in the67// destination buffer68page.getDataAsBytes(startAddress, numBytesFromPage, data, numRead);69// Increment offsets70numRead += numBytesFromPage;71numBytes -= numBytesFromPage;72startAddress += numBytesFromPage;73}7475return data;76}7778public synchronized boolean getBoolean(long address) {79return (getByte(address) != 0);80}8182public synchronized byte getByte(long address) {83return checkPage(getPage(address & pageMask), address).getByte(address);84}8586public synchronized short getShort(long address, boolean bigEndian) {87return checkPage(getPage(address & pageMask), address).getShort(address, bigEndian);88}8990public synchronized char getChar(long address, boolean bigEndian) {91return checkPage(getPage(address & pageMask), address).getChar(address, bigEndian);92}9394public synchronized int getInt(long address, boolean bigEndian) {95return checkPage(getPage(address & pageMask), address).getInt(address, bigEndian);96}9798public synchronized long getLong(long address, boolean bigEndian) {99return checkPage(getPage(address & pageMask), address).getLong(address, bigEndian);100}101102public synchronized float getFloat(long address, boolean bigEndian) {103return checkPage(getPage(address & pageMask), address).getFloat(address, bigEndian);104}105106public synchronized double getDouble(long address, boolean bigEndian) {107return checkPage(getPage(address & pageMask), address).getDouble(address, bigEndian);108}109110/** A mechanism for clearing cached data covering the given region */111public synchronized void clear(long startAddress, long numBytes) {112long pageBaseAddress = startAddress & pageMask;113long endAddress = startAddress + numBytes;114while (pageBaseAddress < endAddress) {115flushPage(pageBaseAddress);116pageBaseAddress += pageSize;117}118}119120/** A mechanism for clearing out the cache is necessary to handle121detaching and reattaching */122public synchronized void clear() {123// Should probably break next/prev links in list as well124addressToPageMap.clear();125lruList = null;126numPages = 0;127}128129/** Disables the page cache; no further pages will be added to the130cache and all existing pages will be flushed. Call this when the131target process has been resumed. */132public synchronized void disable() {133enabled = false;134clear();135}136137/** Enables the page cache; fetched pages will be added to the138cache. Call this when the target process has been suspended. */139public synchronized void enable() {140enabled = true;141}142143144//--------------------------------------------------------------------------------145// Internals only below this point146//147148// This is implemented with two data structures: a hash table for149// fast lookup by a page's base address and a circular doubly-linked150// list for implementing LRU behavior.151152private boolean enabled;153private long pageSize;154private long maxNumPages;155private long pageMask;156private long numPages;157private PageFetcher fetcher;158private LongHashMap addressToPageMap; // Map<long, Page>159private Page lruList; // Most recently fetched page, or null160161/** Page fetcher plus LRU functionality */162private Page getPage(long pageBaseAddress) {163// Check head of LRU list first to avoid hash table lookup and164// extra list work if possible165if (lruList != null) {166if (lruList.getBaseAddress() == pageBaseAddress) {167// Hit. Return it.168return lruList;169}170}171// Long key = new Long(pageBaseAddress);172long key = pageBaseAddress;173Page page = (Page) addressToPageMap.get(key);174if (page == null) {175// System.err.println("** Cache miss at address 0x" + Long.toHexString(pageBaseAddress) + " **");176// Fetch new page177page = fetcher.fetchPage(pageBaseAddress, pageSize);178if (enabled) {179// Add to cache, evicting last element if necessary180addressToPageMap.put(key, page);181if (Assert.ASSERTS_ENABLED) {182Assert.that(page == (Page) addressToPageMap.get(pageBaseAddress),183"must have found page in cache!");184}185addPageToList(page);186// See whether eviction of oldest is necessary187if (numPages == maxNumPages) {188Page evictedPage = lruList.getPrev();189// System.err.println("-> Evicting page at 0x" + Long.toHexString(evictedPage.getBaseAddress()) +190// "; " + countPages() + " pages left (expect " + numPages + ")");191removePageFromList(evictedPage);192addressToPageMap.remove(evictedPage.getBaseAddress());193} else {194++numPages;195}196}197} else {198// Page already in cache, move to front of list199removePageFromList(page);200addPageToList(page);201}202return page;203}204205private Page checkPage(Page page, long startAddress) {206if (!page.isMapped()) {207throw new UnmappedAddressException(startAddress);208}209return page;210}211212private int countPages() {213Page page = lruList;214int num = 0;215if (page == null) {216return num;217}218do {219++num;220page = page.getNext();221} while (page != lruList);222return num;223}224225private void flushPage(long pageBaseAddress) {226long key = pageBaseAddress;227Page page = (Page) addressToPageMap.remove(key);228if (page != null) {229removePageFromList(page);230}231}232233// Adds given page to head of list234private void addPageToList(Page page) {235if (lruList == null) {236lruList = page;237page.setNext(page);238page.setPrev(page);239} else {240// Add to front of list241page.setNext(lruList);242page.setPrev(lruList.getPrev());243lruList.getPrev().setNext(page);244lruList.setPrev(page);245lruList = page;246}247}248249// Removes given page from list250private void removePageFromList(Page page) {251if (page.getNext() == page) {252lruList = null;253} else {254if (lruList == page) {255lruList = page.getNext();256}257page.getPrev().setNext(page.getNext());258page.getNext().setPrev(page.getPrev());259}260page.setPrev(null);261page.setNext(null);262}263264/** Ensure that page size fits within 32 bits and is a power of two, and that maxNumPages > 0 */265private void checkPageInfo(long pageSize, long maxNumPages) {266if ((pageSize <= 0) || maxNumPages <= 0) {267throw new IllegalArgumentException("pageSize and maxNumPages must both be greater than zero");268}269long tmpPageSize = pageSize >>> 32;270if (tmpPageSize != 0) {271throw new IllegalArgumentException("pageSize " + pageSize + " too big (must fit within 32 bits)");272}273int numNonZeroBits = 0;274for (int i = 0; i < 32; ++i) {275if ((pageSize & 1L) != 0) {276++numNonZeroBits;277if ((numNonZeroBits > 1) || (i == 0)) {278throw new IllegalArgumentException("pageSize " + pageSize + " must be a power of two");279}280}281pageSize >>>= 1;282if (numNonZeroBits == 0) {283pageMask = (pageMask << 1) | 1L;284}285}286pageMask = ~pageMask;287}288}289290291