/*
* Copyright (c) 2010, 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.method;
import java.lang.ref.*;
import java.util.*;
import com.sun.max.tele.*;
import com.sun.max.tele.object.*;
import com.sun.max.tele.object.TeleTargetMethod.*;
import com.sun.max.tele.util.*;
import com.sun.max.unsafe.*;
import com.sun.max.vm.code.*;
import com.sun.max.vm.compiler.target.*;
import com.sun.max.vm.type.*;
/**
* A manager for pointers to machine code allocated in a {@link SemiSpaceCodeRegion}.
* This manager:
* <ul>
* <li>assumes that machine code allocated can be relocated and eventually collected/evicted.</li>
* <li>assumes that there can only be code in the region of the kind managed and described by
* (heap) object instances of {@link TeleMethodActor}.</li>
* <li>creates <em>canonical pointers</em>.
* </ul>
* This implementation depends on knowledge of the internal workings of {@link TargetMethod}.
*
* @see TargetMethod
* @see VmCodeCacheRegion
* @see TeleTargetMethod
*/
public class SemispaceCodeCacheRemoteCodePointerManager extends AbstractRemoteCodePointerManager {
private final VmCodeCacheRegion codeCacheRegion;
/**
* A two level map. For each compilation for which code pointers have been created,
* map integers (offset into the byte array containing code) to code pointers.
* <pre>
* Compilation --> [ Integer --> WeakReference<RemoteCodePointer> ]
* </pre>
*/
private final Map<TeleCompilation, Map<Integer, WeakReference<RelativeRemoteCodePointer> > > pointerMaps =
new HashMap<TeleCompilation, Map<Integer, WeakReference<RelativeRemoteCodePointer> > >();
/**
* Creates a manager for pointers to machine code a particular region
* of memory in the VM, presumed to be an unmanaged region in which code
* never moves and is never evicted.
*/
public SemispaceCodeCacheRemoteCodePointerManager(TeleVM vm, VmCodeCacheRegion codeCacheRegion) {
super(vm);
this.codeCacheRegion = codeCacheRegion;
}
public MaxCodeHoldingRegion codeRegion() {
return codeCacheRegion;
}
public boolean isValidCodePointer(Address address) throws TeleError {
TeleError.check(codeCacheRegion.memoryRegion().contains(address), "Location is outside region");
final TeleCompilation compilation = codeCacheRegion.findCompilation(address);
if (compilation != null) {
return compilation.isValidCodeLocation(address);
}
return false;
}
public RemoteCodePointer makeCodePointer(Address address) throws TeleError {
TeleError.check(codeCacheRegion.memoryRegion().contains(address), "Location is outside region");
final TeleCompilation compilation = codeCacheRegion.findCompilation(address);
if (compilation == null || !compilation.isValidCodeLocation(address)) {
return null;
}
RelativeRemoteCodePointer codePointer = null;
final TeleTargetMethod teleTargetMethod = compilation.teleTargetMethod();
final Address codeByteArrayOrigin = teleTargetMethod.codeCacheObjectOrigin(CodeCacheReferenceKind.CODE);
final int codeOffset = objects().unsafeArrayElementAddressToIndex(Kind.BYTE, codeByteArrayOrigin, address);
Map<Integer, WeakReference<RelativeRemoteCodePointer>> pointerMap = pointerMaps.get(compilation);
if (pointerMap == null) {
pointerMap = new HashMap<Integer, WeakReference<RelativeRemoteCodePointer> >();
pointerMaps.put(compilation, pointerMap);
} else {
final WeakReference<RelativeRemoteCodePointer> weakReference = pointerMap.get(codeOffset);
if (weakReference != null) {
codePointer = weakReference.get();
}
}
if (codePointer == null) {
codePointer = new RelativeRemoteCodePointer(teleTargetMethod, codeOffset);
pointerMap.put(codeOffset, new WeakReference<RelativeRemoteCodePointer>(codePointer));
}
return codePointer;
}
public int activePointerCount() {
int count = 0;
for (Map<Integer, WeakReference<RelativeRemoteCodePointer>> pointerMap : pointerMaps.values()) {
for (WeakReference<RelativeRemoteCodePointer> weakReference : pointerMap.values()) {
if (weakReference.get() != null) {
count++;
}
}
}
return count;
}
public int totalPointerCount() {
int count = 0;
for (Map<Integer, WeakReference<RelativeRemoteCodePointer>> pointerMap : pointerMaps.values()) {
count += pointerMap.size();
}
return count;
}
/**
* A pointer a machine code location in a VM method compilation, represented as an
* offset relative to the beginning of the code array so that it can track possible
* code location.
*/
private final class RelativeRemoteCodePointer implements RemoteCodePointer {
private final TeleTargetMethod teleTargetMethod;
private final int codeOffset;
public RelativeRemoteCodePointer(TeleTargetMethod teleTargetMethod, int codeOffset) {
this.teleTargetMethod = teleTargetMethod;
this.codeOffset = codeOffset;
}
public Address getAddress() {
if (teleTargetMethod.status().isLive()) {
final Address codeByteArrayOrigin = teleTargetMethod.codeCacheObjectOrigin(CodeCacheReferenceKind.CODE);
return objects().unsafeArrayIndexToAddress(Kind.BYTE, codeByteArrayOrigin, codeOffset);
}
return Address.zero();
}
public boolean isCodeLive() {
return !teleTargetMethod.isCodeEvicted();
}
}
}