/*
* Copyright (c) 2007, 2012, 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.
*/
package com.sun.max.tele.page;
import java.nio.*;
import java.util.*;
import com.sun.max.lang.*;
import com.sun.max.program.*;
import com.sun.max.tele.*;
import com.sun.max.tele.data.*;
import com.sun.max.tele.debug.*;
import com.sun.max.tele.util.*;
import com.sun.max.unsafe.*;
/**
*/
public class PageDataAccess extends DataAccessAdapter {
private static final int TRACE_VALUE = 1;
protected String tracePrefix() {
return "[PageDataAccess] ";
}
private final TeleVM vm;
private final TeleIO teleIO;
private final int indexShift;
private final int offsetMask;
private final ByteBuffer writeBuffer;
public PageDataAccess(TeleVM vm, TeleIO teleProcess, DataModel dataModel) {
super(dataModel.wordWidth, dataModel.endianness.asByteOrder());
this.vm = vm;
teleIO = teleProcess;
TeleError.check(Ints.isPowerOfTwoOrZero(teleIO.pageSize()), "Page size is not a power of 2: " + teleIO.pageSize());
indexShift = Integer.numberOfTrailingZeros(teleProcess.pageSize());
offsetMask = teleProcess.pageSize() - 1;
writeBuffer = ByteBuffer.wrap(new byte[Longs.SIZE]).order(byteOrder);
}
public int pageSize() {
return teleIO.pageSize();
}
private long getIndex(Address address) {
return address.toLong() >>> indexShift;
}
private int getOffset(Address address) {
return address.toInt() & offsetMask;
}
private final HashMap<Long, Page> indexToPage = new HashMap<Long, Page>();
private static void checkNullPointer(Address address) {
if (address.isZero()) {
throw new DataIOError(address, "Cannot access address ZERO");
}
}
private void invalidatePage(long index) {
final Page page = indexToPage.get(index);
if (page != null) {
page.invalidate();
}
}
public synchronized void invalidate(Address address, Size size) {
long numberOfPages = getIndex(size);
if (getOffset(address) + getOffset(size) > pageSize()) {
numberOfPages++;
}
final long startIndex = getIndex(address);
for (long index = startIndex; index <= startIndex + numberOfPages; index++) {
invalidatePage(index);
}
}
public void invalidateForWrite(Address address, int size) {
checkNullPointer(address);
invalidate(address, Size.fromInt(size));
}
private Page getPage(long index) {
Page page = indexToPage.get(index);
if (page == null) {
page = new Page(vm, teleIO, index, byteOrder);
indexToPage.put(index, page);
if ((indexToPage.size() % 1000) == 0) {
Trace.line(TRACE_VALUE, tracePrefix() + "Memory cache: " + indexToPage.size() + " pages");
}
}
return page;
}
private Page getPage(Address address) {
return getPage(getIndex(address));
}
public synchronized int read(Address address, ByteBuffer buffer, int offset, int length) {
final int toRead = Math.min(length, buffer.limit() - offset);
long pageIndex = getIndex(address);
int pageOffset = getOffset(address);
int i = 0;
while (i < toRead) {
i += getPage(pageIndex).readBytes(pageOffset, buffer, i + offset);
pageIndex++;
pageOffset = 0;
}
return toRead;
}
public synchronized byte readByte(Address address) {
checkNullPointer(address);
return getPage(address).readByte(getOffset(address));
}
public synchronized short readShort(Address address) {
checkNullPointer(address);
return getPage(address).readShort(getOffset(address));
}
public synchronized int readInt(Address address) {
checkNullPointer(address);
return getPage(address).readInt(getOffset(address));
}
public long readLong(Address address) {
checkNullPointer(address);
return getPage(address).readLong(getOffset(address));
}
public synchronized int write(ByteBuffer buffer, int offset, int length, Address address) {
try {
invalidateForWrite(address, buffer.limit());
DataIO.Static.checkRead(buffer, offset, length);
return teleIO.write(buffer, offset, buffer.limit(), address);
} catch (TerminatedProcessIOException e) {
return length;
}
}
public synchronized void writeByte(Address address, byte value) {
try {
invalidateForWrite(address, Bytes.SIZE);
writeBuffer.put(0, value);
teleIO.write(writeBuffer, 0, Bytes.SIZE, address);
} catch (TerminatedProcessIOException e) {
}
}
public synchronized void writeShort(Address address, short value) {
try {
invalidateForWrite(address, Shorts.SIZE);
writeBuffer.putShort(0, value);
teleIO.write(writeBuffer, 0, Shorts.SIZE, address);
} catch (TerminatedProcessIOException e) {
}
}
public synchronized void writeInt(Address address, int value) {
try {
invalidateForWrite(address, Ints.SIZE);
writeBuffer.putInt(0, value);
teleIO.write(writeBuffer, 0, Ints.SIZE, address);
} catch (TerminatedProcessIOException e) {
}
}
public synchronized void writeLong(Address address, long value) {
try {
invalidateForWrite(address, Longs.SIZE);
writeBuffer.putLong(0, value);
teleIO.write(writeBuffer, 0, Longs.SIZE, address);
} catch (TerminatedProcessIOException e) {
}
}
}