/*
* 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.vm.code;
import java.util.*;
import com.sun.max.annotate.*;
import com.sun.max.program.*;
import com.sun.max.unsafe.*;
import com.sun.max.vm.*;
import com.sun.max.vm.compiler.target.*;
import com.sun.max.vm.heap.*;
import com.sun.max.vm.heap.debug.*;
import com.sun.max.vm.runtime.*;
/**
* A code region with semi-space characteristics.
*/
public final class SemiSpaceCodeRegion extends CodeRegion {
public SemiSpaceCodeRegion(String description) {
super(description);
fromTargetMethods = new TargetMethod[DEFAULT_CAPACITY];
fromLength = 0;
fromFindIndex = new int[DEFAULT_CAPACITY];
}
@INSPECTED
protected Address toSpace;
@INSPECTED
protected Address fromSpace;
@INSPECTED
protected Size spaceSize;
@INSPECTED
protected Address topOfSpace;
/**
* Stores the target methods in from-space.
* The {@link #targetMethods} array stores target methods in to-space.
*/
@INSPECTED
protected TargetMethod[] fromTargetMethods;
/**
* A {@link #findIndex} for from-space.
*/
private int[] fromFindIndex;
/**
* Amount of entries in the from-space target methods array.
* The {@link #length} field represents the amount of entries in to-space.
*/
@INSPECTED
protected int fromLength;
/**
* Binds this code region to some allocated memory range and sets the semi-space addresses.
*
* @param start the start address of the range
* @param size the size of the memory range
*/
@Override
public void bind(Address start, Size size) {
this.start = start;
this.size = size;
this.toSpace = start;
this.spaceSize = size.dividedBy(2);
this.fromSpace = toSpace.plus(spaceSize);
this.topOfSpace = toSpace.plus(spaceSize);
this.mark.set(toSpace);
}
/**
* Gets the GC start.
* For semi-space code regions, the GC start is to-space start.
*/
@Override
public Address gcstart() {
return toSpace;
}
/**
* Flip to-space and from-space, set topOfSpace accordingly.
*/
public void flip() {
Address tmpSpace = toSpace;
toSpace = fromSpace;
fromSpace = tmpSpace;
topOfSpace = toSpace.plus(spaceSize);
mark.set(toSpace);
TargetMethod[] tmpMethods = targetMethods;
targetMethods = fromTargetMethods;
fromTargetMethods = tmpMethods;
int tmpLength = length;
length = fromLength;
fromLength = tmpLength;
int[] tmpIndex = findIndex;
findIndex = fromFindIndex;
fromFindIndex = tmpIndex;
}
/**
* Allocates some memory from this region. See {@linkplain LinearAllocatorRegion} for details.
*/
@Override
public Pointer allocate(Size size, boolean adjustForDebugTag) {
if (!size.isWordAligned()) {
FatalError.unexpected("Allocation size must be word aligned");
}
Pointer oldAllocationMark = mark();
Pointer cell = adjustForDebugTag ? DebugHeap.adjustForDebugTag(oldAllocationMark) : oldAllocationMark;
Address end = cell.plus(size);
if (end.greaterThan(topOfSpace)) {
if (MaxineVM.isHosted()) {
ProgramError.unexpected("out of space in linear allocator region");
}
return Pointer.zero();
}
setMark(end);
return cell;
}
/**
* Looks up the target method containing a particular address <i>in from-space</i>.
*/
public TargetMethod findInFromSpace(Address cp) {
if (!isInFromSpace(cp)) {
return null;
}
return find0(cp, fromSpace, fromFindIndex, fromTargetMethods);
}
@Override
protected boolean validMethodStart(TargetMethod tm, Address address) {
return isInFromSpace(address) ? tm.oldStart().lessEqual(address) : super.validMethodStart(tm, address);
}
@Override
protected boolean methodFound(TargetMethod tm, Address address) {
if (isInFromSpace(address)) {
final Address start = tm.oldStart();
return start.lessEqual(address) && start.plus(tm.size()).greaterThan(address);
} else {
return super.methodFound(tm, address);
}
}
/**
* Controls whether {@code #find()} will also take from-space into account.
* This is to be used with extreme care. It is intended to be used during code eviction only.
*/
public boolean allowFromSpaceLookup = false;
/**
* Looks up the target method containing a particular address (using binary search).
* This specialised version for a semi-space code region checks whether the passed address is in from-space.
* If so, it looks for the address in from-space first, but only if the {@code allowFromSpaceLookup} field is set to {@code true}.
* This must be the case only during code eviction.
*
* @param cp the address to lookup in this region
* @return a reference to the target method containing the specified address, if it exists; {@code null} otherwise
*/
@Override
public TargetMethod find(Address cp) {
final boolean addressInFromSpace = isInFromSpace(cp);
if (allowFromSpaceLookup) {
final TargetMethod fromSpaceLookup = findInFromSpace(cp);
if (fromSpaceLookup != null) {
return fromSpaceLookup;
}
return super.find(cp);
} else {
if (addressInFromSpace) {
return null;
} else {
return super.find(cp);
}
}
}
public boolean isInFromSpace(Address a) {
return fromSpace.lessEqual(a) && fromSpace.plus(spaceSize).greaterThan(a);
}
public boolean isInToSpace(Address a) {
return toSpace.lessEqual(a) && topOfSpace.greaterThan(a);
}
/**
* Adds a method to this code region.
* This specialises the implementation in {@code CodeRegion} in that the {@link #fromTargetMethods} array
* grows along with the {@link #targetMethods} array.
*/
@Override
public void add(TargetMethod tm) {
final TargetMethod[] tms = targetMethods;
final int[] index = findIndex;
super.add(tm);
if (tms != targetMethods) {
fromTargetMethods = Arrays.copyOf(fromTargetMethods, targetMethods.length);
}
if (index != findIndex) {
fromFindIndex = Arrays.copyOf(fromFindIndex, findIndex.length);
}
}
/**
* Reset the from-space target methods array.
*/
public void resetFromSpace() {
Arrays.fill(fromTargetMethods, null);
fromLength = 0;
Arrays.fill(fromFindIndex, 0);
}
/**
* Process each target method in this region's to-space with a given closure.
*/
public boolean doNewTargetMethods(TargetMethod.Closure c) {
TargetMethod[] targetMethods = this.targetMethods;
assert length <= targetMethods.length;
for (int i = 0; i < length; i++) {
TargetMethod targetMethod = targetMethods[i];
if (targetMethod != null && isInToSpace(targetMethod.codeStart().toAddress()) && !c.doTargetMethod(targetMethod)) {
return false;
}
}
return true;
}
/**
* Process each target method in this region's from-space with a given closure.
*/
public boolean doOldTargetMethods(TargetMethod.Closure c) {
TargetMethod[] tms = this.fromTargetMethods;
assert fromLength <= tms.length;
for (int i = 0; i < fromLength; i++) {
TargetMethod targetMethod = tms[i];
if (targetMethod != null && isInFromSpace(targetMethod.codeStart().toAddress()) && !c.doTargetMethod(targetMethod)) {
return false;
}
}
return true;
}
}