/*
* 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.stack;
import static com.sun.max.vm.MaxineVM.*;
import static com.sun.max.vm.intrinsics.Infopoints.*;
import static com.sun.max.vm.runtime.VMRegister.*;
import static com.sun.max.vm.thread.VmThreadLocal.*;
import static com.sun.max.vm.intrinsics.MaxineIntrinsicIDs.*;
import java.util.concurrent.atomic.*;
import com.oracle.max.cri.intrinsics.*;
import com.sun.cri.ci.*;
import com.sun.max.annotate.*;
import com.sun.max.lang.*;
import com.sun.max.unsafe.*;
import com.sun.max.util.timer.*;
import com.sun.max.vm.*;
import com.sun.max.vm.log.VMLog.Record;
import com.sun.max.vm.log.*;
import com.sun.max.vm.log.VMLogger.Interval;
import com.sun.max.vm.log.hosted.*;
import com.sun.max.vm.bytecode.refmaps.*;
import com.sun.max.vm.compiler.target.*;
import com.sun.max.vm.heap.*;
import com.sun.max.vm.reference.*;
import com.sun.max.vm.runtime.*;
import com.sun.max.vm.thread.*;
import com.sun.max.vm.type.*;
/**
* GC support: prepares the object reference map of a thread's stack.
* Sets one bit in the map for each slot on the stack that contains an object reference.
* The map is located on the stack above the safepoints-triggered VM thread locals.
* The map covers two address ranges: the first is the safepoints-triggered VM thread local and the
* second is the portion of the stack "in use" which extends from the current stack pointer (regarded as "stack top")
* to the end of the safepoints-enabled VM thread locals (regarded as "stack bottom").
* The latter region extends from the stack pointer up to the end of the safepoints-enabled VM thread locals.
* The diagram {@linkplain VmThread here} depicts where the reference map is on the stack as well as the regions
* it covers.
* <p>
* The lowest bit in the map corresponds to the first word of the safepoints-triggered VM thread locals.
* The {@code n}th bit corresponds to the stack top where {@code n == NUMBER_OF_REFERENCE_MAP_SLOTS_FOR_TRIGGERED_VM_THREAD_LOCALS}.
* The highest bit in the map corresponds to the stack bottom.
* <p>
* The GC's root scanning can then simply iterate over the bits in the map to find all object references on the stack.
* Thus the GC does not need to allocate any auxiliary data during root scanning,
* nor does it need to traverse any objects.
* This provides a lot of flexibility in GC implementation.
*
* ATTENTION: the algorithm below must not allocate any objects from the GC heap,
* since it is running at a GC safepoint when the global GC lock may already be taken.
* Especially the {@linkplain ReferenceMapInterpreter reference map interpreter},
* which fills in stack reference maps for target methods compiled by the baseline compiler as needed
* was carefully crafted to comply with this requirement.
*/
public final class StackReferenceMapPreparer extends FrameReferenceMapVisitor {
/**
* Disables stack root scanning if greater than 0.
*/
private static int LogSRSSuppressionCount;
/**
* A counter used purely for {@link #LogSRSSuppressionCount}.
*/
private static AtomicInteger SRSCount = new AtomicInteger();
static {
VMOptions.addFieldOption("-XX:", "LogSRSSuppressionCount", "Disable logging of the first n stack root scans.");
}
/**
* Determines if stack root scanning should be logged.
*/
public static boolean logStackRootScanning() {
return Heap.logRootScanning() || (stackRootScanLogger.enabled() && LogSRSSuppressionCount <= 0);
}
public static boolean VerifyRefMaps;
static {
VMOptions.addFieldOption("-XX:", "VerifyRefMaps", StackReferenceMapPreparer.class,
"Verify reference maps by performing a stack walk and checking plausibility of reference roots in " +
"the stack--as often as possible.", MaxineVM.Phase.PRISTINE);
}
private final Timer timer = new SingleUseTimer(HeapScheme.GC_TIMING_CLOCK);
private Pointer ttla;
private Pointer referenceMap;
private Pointer lowestStackSlot;
private Pointer completingReferenceMapLimit;
private final boolean verify;
private final boolean prepare;
private long preparationTime;
/**
* This is used to skip preparation of the reference map for the top frame on a stack. This is
* used when a GC thread prepares its own stack reference map as the frame initiating the
* preparation will be dead once the GC actual starts.
*
* @see VmThreadLocal#prepareCurrentStackReferenceMap()
*/
private boolean ignoreCurrentFrame;
public StackReferenceMapPreparer(boolean verify, boolean prepare) {
this.verify = verify;
this.prepare = prepare;
}
private static Pointer slotAddress(int slotIndex, Pointer tla) {
return LOWEST_STACK_SLOT_ADDRESS.load(tla).plusWords(slotIndex);
}
/**
* Clear a range of bits in the reference map. The reference map bits at indices in the inclusive range
* {@code [lowestSlotIndex .. highestSlotIndex]} are zeroed. No other bits in the reference map are modified.
*
* @param tla a pointer to the VM thread locals corresponding to the stack to scan
* @param lowestSlot the address of the lowest slot to clear
* @param highestSlot the address of the highest slot to clear
*/
public static void clearReferenceMapRange(Pointer tla, Pointer lowestSlot, Pointer highestSlot) {
checkValidReferenceMapRange(tla, lowestSlot, highestSlot);
Pointer lowestStackSlot = LOWEST_STACK_SLOT_ADDRESS.load(tla);
Pointer referenceMap = STACK_REFERENCE_MAP.load(tla);
int highestRefMapByteIndex = referenceMapByteIndex(lowestStackSlot, highestSlot);
int lowestRefMapByteIndex = referenceMapByteIndex(lowestStackSlot, lowestSlot);
// Handle the lowest and highest reference map bytes separately as they may contain bits
// for slot addresses lower than 'lowestSlot' and higher than 'highestSlot' respectively.
// These bits must be preserved.
int lowestBitIndex = referenceMapBitIndex(lowestStackSlot, lowestSlot);
int highestBitIndex = referenceMapBitIndex(lowestStackSlot, highestSlot);
int lowestRefMapBytePreservedBits = ~Ints.highBitsSet(lowestBitIndex % Bytes.WIDTH);
int highestRefMapBytePreservedBits = ~Ints.lowBitsSet(highestBitIndex % Bytes.WIDTH);
if (lowestRefMapByteIndex == highestRefMapByteIndex) {
byte singleRefMapByte = referenceMap.readByte(lowestRefMapByteIndex);
int singleRefMapBytePreservedBits = lowestRefMapBytePreservedBits | highestRefMapBytePreservedBits;
referenceMap.writeByte(lowestRefMapByteIndex, (byte) (singleRefMapByte & singleRefMapBytePreservedBits));
} else {
byte lowestRefMapByte = referenceMap.readByte(lowestRefMapByteIndex);
byte highestRefMapByte = referenceMap.readByte(highestRefMapByteIndex);
lowestRefMapByte = (byte) (lowestRefMapByte & lowestRefMapBytePreservedBits);
highestRefMapByte = (byte) (highestRefMapByte & highestRefMapBytePreservedBits);
referenceMap.writeByte(lowestRefMapByteIndex, lowestRefMapByte);
referenceMap.writeByte(highestRefMapByteIndex, highestRefMapByte);
for (int refMapByteIndex = lowestRefMapByteIndex + 1; refMapByteIndex < highestRefMapByteIndex; refMapByteIndex++) {
referenceMap.writeByte(refMapByteIndex, (byte) 0);
}
}
if (logStackRootScanning()) {
StackReferenceMapPreparer.stackRootScanLogger.logClearedRefMapIndexes(lowestBitIndex, highestBitIndex);
}
}
/**
* Scan references in the stack in the specified interval [lowestSlot, highestSlot].
*
* @param tla a pointer to the VM thread locals corresponding to the stack to scan
* @param lowestSlot the address of the lowest slot to scan
* @param highestSlot the address of the highest slot to scan
* @param wordPointerIndexVisitor the visitor to apply to each slot that is a reference
*/
public static void scanReferenceMapRange(Pointer tla, Pointer lowestSlot, Pointer highestSlot, PointerIndexVisitor wordPointerIndexVisitor) {
checkValidReferenceMapRange(tla, lowestSlot, highestSlot);
Pointer lowestStackSlot = LOWEST_STACK_SLOT_ADDRESS.load(tla);
Pointer referenceMap = STACK_REFERENCE_MAP.load(tla);
int highestRefMapByteIndex = referenceMapByteIndex(lowestStackSlot, highestSlot);
int lowestRefMapByteIndex = referenceMapByteIndex(lowestStackSlot, lowestSlot);
// Handle the lowest reference map byte separately as it may contain bits
// for slot addresses lower than 'lowestSlot'. These bits must be ignored:
int lowestBitIndex = referenceMapBitIndex(lowestStackSlot, lowestSlot);
int highestBitIndex = referenceMapBitIndex(lowestStackSlot, highestSlot);
if (highestRefMapByteIndex == lowestRefMapByteIndex) {
scanReferenceMapByte(lowestRefMapByteIndex, lowestStackSlot, referenceMap, lowestBitIndex % Bytes.WIDTH, (highestBitIndex % Bytes.WIDTH) + 1, tla, wordPointerIndexVisitor);
} else {
scanReferenceMapByte(lowestRefMapByteIndex, lowestStackSlot, referenceMap, lowestBitIndex % Bytes.WIDTH, Bytes.WIDTH, tla, wordPointerIndexVisitor);
scanReferenceMapByte(highestRefMapByteIndex, lowestStackSlot, referenceMap, 0, (highestBitIndex % Bytes.WIDTH) + 1, tla, wordPointerIndexVisitor);
for (int refMapByteIndex = lowestRefMapByteIndex + 1; refMapByteIndex < highestRefMapByteIndex; refMapByteIndex++) {
scanReferenceMapByte(refMapByteIndex, lowestStackSlot, referenceMap, 0, Bytes.WIDTH, tla, wordPointerIndexVisitor);
}
}
}
private static void scanReferenceMapByte(int refMapByteIndex, Pointer lowestStackSlot, Pointer referenceMap, int startBit, int endBit, Pointer tla, PointerIndexVisitor wordPointerIndexVisitor) {
int refMapByte = referenceMap.getByte(refMapByteIndex);
if (refMapByte != 0) {
int baseIndex = refMapByteIndex * Bytes.WIDTH;
for (int bitIndex = startBit; bitIndex < endBit; bitIndex++) {
if (((refMapByte >>> bitIndex) & 1) != 0) {
int stackWordIndex = baseIndex + bitIndex;
if (logStackRootScanning()) {
stackRootScanLogger.logStackSlot(stackWordIndex, tla, Pointer.zero(), true);
}
if (!Reference.fromOrigin(slotAddress(stackWordIndex, tla).readWord(0).asPointer()).isTagged()) {
// only visit non-tagged references
wordPointerIndexVisitor.visit(lowestStackSlot, stackWordIndex);
}
}
}
}
}
@INLINE
private static int referenceMapByteIndex(final Pointer lowestStackSlot, Pointer slot) {
return UnsignedMath.divide(referenceMapBitIndex(lowestStackSlot, slot), Bytes.WIDTH);
}
@INLINE
private static int referenceMapBitIndex(final Pointer lowestStackSlot, Pointer slot) {
return UnsignedMath.divide(slot.minus(lowestStackSlot).toInt(), Word.size());
}
private static void checkValidReferenceMapRange(Pointer tla, Pointer lowestSlot, Pointer highestSlot) {
Pointer lowestStackSlot = LOWEST_STACK_SLOT_ADDRESS.load(tla);
Pointer highestStackSlot = HIGHEST_STACK_SLOT_ADDRESS.load(tla);
String error = null;
if (highestSlot.lessThan(lowestSlot)) {
error = "invalid reference map range: highest slot is less than lowest slot";
} else if (highestSlot.greaterThan(highestStackSlot)) {
error = "invalid reference map range: highest slot is greater than highest stack slot";
} else if (lowestSlot.lessThan(lowestStackSlot)) {
error = "invalid reference map range: lowest slot is less than lowest stack slot";
}
if (error != null) {
Log.print("Error building reference map for stack of thread ");
Log.printThread(VmThread.fromTLA(tla), false);
Log.print(": ");
Log.println(error);
FatalError.unexpected(error);
}
}
/**
* Gets the time taken for the last call to {@link #prepareStackReferenceMap(Pointer)}.
* If there was an interleaving call to {@link #completeStackReferenceMap(com.sun.max.unsafe.Pointer)} completeStackReferenceMap(Pointer, Pointer, Pointer, Pointer)}, then that
* time is included as well. That is, this method gives the amount of time spent preparing the stack
* reference map for the associated thread during the last/current GC.
*
* @return a time in the resolution specified by {@link HeapScheme#GC_TIMING_CLOCK}
*/
public long preparationTime() {
return preparationTime;
}
/**
* Prepares a reference map for the entire stack of a VM thread
* while the GC has not changed anything yet.
*
* Later on, the GC can quickly scan the prepared stack reference map
* without allocation and without using any object references (other than the ones subject to root scanning).
*
* @param tla
* @param instructionPointer
* @param stackPointer
* @param framePointer
* @param ignoreTopFrame specifies if the top frame is to be ignored
* @return the amount of time (in the resolution specified by {@link HeapScheme#GC_TIMING_CLOCK}) taken to prepare the reference map
*/
public long prepareStackReferenceMap(Pointer tla, CodePointer instructionPointer, Pointer stackPointer, Pointer framePointer, boolean ignoreTopFrame) {
timer.start();
ignoreCurrentFrame = ignoreTopFrame;
initRefMapFields(tla);
Pointer highestStackSlot = HIGHEST_STACK_SLOT_ADDRESS.load(tla);
// Inform subsequent reference map scanning (see VmThreadLocal.scanReferences()) of the stack range covered:
LOWEST_ACTIVE_STACK_SLOT_ADDRESS.store3(tla, stackPointer);
VmThread vmThread = VmThread.fromTLA(tla);
if (this != vmThread.stackReferenceMapPreparer()) {
FatalError.unexpected("Cannot use stack reference map preparer of another thread");
}
// clear the reference map covering the stack contents
clearReferenceMapRange(tla, stackPointer, highestStackSlot);
boolean lockDisabledSafepoints = logStackRootScanStart(stackPointer, highestStackSlot, vmThread);
// walk the stack and prepare references for each stack frame
StackFrameWalker sfw = vmThread.referenceMapPreparingStackFrameWalker();
sfw.prepareReferenceMap(instructionPointer.toPointer(), stackPointer, framePointer, this);
logStackRootScanEnd(lockDisabledSafepoints);
timer.stop();
preparationTime = timer.getLastElapsedTime();
return preparationTime;
}
private void logStackRootScanEnd(boolean lockDisabledSafepoints) {
if (logStackRootScanning()) {
stackRootScanLogger.unlock(lockDisabledSafepoints);
}
}
private boolean logStackRootScanStart(Pointer stackPointer, Pointer highestStackSlot, VmThread vmThread) {
// Ideally this test and decrement should be atomic but it's ok
// for LogSRSSuppressionCount to be approximate
if (LogSRSSuppressionCount > 0) {
LogSRSSuppressionCount--;
}
SRSCount.incrementAndGet();
if (logStackRootScanning()) {
boolean lockDisabledSafepoints = stackRootScanLogger.lock();
stackRootScanLogger.logStart(
SRSCount.get(),
prepare,
stackPointer,
highestStackSlot,
lowestStackSlot,
vmThread,
referenceMapBitIndex(highestStackSlot),
referenceMapBitIndex(stackPointer),
referenceMapBitIndex(lowestStackSlot));
return lockDisabledSafepoints;
}
return false;
}
private void initRefMapFields(Pointer tla) {
ttla = TTLA.load(tla);
referenceMap = STACK_REFERENCE_MAP.load(tla);
lowestStackSlot = LOWEST_STACK_SLOT_ADDRESS.load(tla);
}
/**
* Completes the stack reference map for a thread that was suspended by a safepoint while executing Java code. The
* reference map covering the stack between the frame in which the safepoint trap occurred and the JNI stub that
* enters into the native code for blocking on the global {@linkplain VmThreadMap#THREAD_LOCK thread lock} is not yet
* prepared. This method completes this part of the threads stack reference map.
*
* @param tla the VM thread locals for the thread whose stack reference map is to be completed
*/
public void completeStackReferenceMap(Pointer tla) {
timer.start();
FatalError.check(!ignoreCurrentFrame, "All frames should be scanned when competing a stack reference map");
Pointer etla = ETLA.load(tla);
Pointer anchor = LAST_JAVA_FRAME_ANCHOR.load(etla);
CodePointer instructionPointer = CodePointer.from(JavaFrameAnchor.PC.get(anchor));
Pointer stackPointer = JavaFrameAnchor.SP.get(anchor);
Pointer framePointer = JavaFrameAnchor.FP.get(anchor);
if (instructionPointer.isZero()) {
FatalError.unexpected("A mutator thread in Java at safepoint should be blocked on a monitor");
}
Pointer highestSlot = LOWEST_ACTIVE_STACK_SLOT_ADDRESS.load(tla);
// Inform subsequent reference map scanning (see VmThreadLocal.scanReferences()) of the stack range covered:
LOWEST_ACTIVE_STACK_SLOT_ADDRESS.store3(tla, stackPointer);
VmThread vmThread = VmThread.fromTLA(tla);
if (this != vmThread.stackReferenceMapPreparer()) {
FatalError.unexpected("Cannot use stack reference map preparer of another thread");
}
// clear the reference map covering the as-yet-unprepared stack contents
clearReferenceMapRange(tla, stackPointer, highestSlot.minus(Word.size()));
boolean lockDisabledSafepoints = false;
if (logStackRootScanning()) {
stackRootScanLogger.logComplete(
vmThread,
highestSlot,
referenceMapBitIndex(stackPointer),
stackPointer,
referenceMapBitIndex(stackPointer),
lowestStackSlot,
referenceMapBitIndex(lowestStackSlot));
}
// walk the stack and prepare references for each stack frame
StackFrameWalker sfw = vmThread.referenceMapPreparingStackFrameWalker();
completingReferenceMapLimit = highestSlot;
sfw.prepareReferenceMap(instructionPointer.toPointer(), stackPointer, framePointer, this);
completingReferenceMapLimit = Pointer.zero();
logStackRootScanEnd(lockDisabledSafepoints);
timer.stop();
preparationTime += timer.getLastElapsedTime();
}
/**
* Gets the lowest stack address for which a stack map has already been completed.
* A zero return value indicates that this preparer is not currently in a call to {@link #completeStackReferenceMap(Pointer)}.
*/
public Pointer completingReferenceMapLimit() {
return completingReferenceMapLimit;
}
public void setReferenceMapBit(Pointer slotAddress) {
referenceMap.setBit(referenceMapBitIndex(lowestStackSlot, slotAddress));
}
/**
* Prepares a reference map for the entire stack of a VM thread executing or blocked in native code.
*
* @param tla a pointer to the VM thread locals denoting the thread stack whose reference map is to be prepared
*/
public void prepareStackReferenceMap(Pointer tla) {
Pointer etla = ETLA.load(tla);
Pointer anchor = LAST_JAVA_FRAME_ANCHOR.load(etla);
if (anchor.isZero()) {
// This is a thread that has returned from VmThread.run() but has not
// yet been terminated via a call to VmThread.detach(). In this state,
// it has no Java stack frames that need scanning.
if (logStackRootScanning()) {
StackReferenceMapPreparer.stackRootScanLogger.logEmptyMap(VmThread.fromTLA(tla));
}
return;
}
CodePointer instructionPointer = CodePointer.from(JavaFrameAnchor.PC.get(anchor));
Pointer stackPointer = JavaFrameAnchor.SP.get(anchor);
Pointer framePointer = JavaFrameAnchor.FP.get(anchor);
if (instructionPointer.isZero()) {
FatalError.unexpected("Thread is not stopped");
}
prepareStackReferenceMap(tla, instructionPointer, stackPointer, framePointer, false);
}
/**
* Prepares a reference map for the stack of a VM thread that was stopped by a safepoint. This method
* prepares the reference map for all the frames starting with the one in which the trap occurred and
* ending with the frame for {@link VmThread#run}.
*
* @param tla a pointer to the VM thread locals denoting the thread stack whose reference map is to be prepared
* @param trapFrame the trap state
*/
public void prepareStackReferenceMapFromTrap(Pointer tla, Pointer trapFrame) {
final TrapFrameAccess tfa = vm().trapFrameAccess;
final Pointer instructionPointer = tfa.getPC(trapFrame);
final Pointer stackPointer = tfa.getSP(trapFrame);
final Pointer framePointer = tfa.getFP(trapFrame);
prepareStackReferenceMap(tla, CodePointer.from(instructionPointer), stackPointer, framePointer, false);
}
/**
* Gets the address of a stack slot given a slot index.
*
* @param slotIndex the slot index for which the address is requested
* @return the address of the stack slot denoted by {@code slotIndex}
*/
private Pointer slotAddress(int slotIndex) {
return lowestStackSlot.plusWords(slotIndex);
}
@Override
public void logPrepareReferenceMap(TargetMethod targetMethod, int safepointIndex, Pointer refmapFramePointer, String label) {
if (logStackRootScanning()) {
stackRootScanLogger.logPrepare(prepare, targetMethod, safepointIndex, refmapFramePointer, label,
referenceMapBitIndex(refmapFramePointer), ttla);
}
}
/**
* If {@linkplain Heap#logRootScanning() GC tracing} is enabled, then this method logs one byte's worth
* of a frame/register reference map.
*
* @param byteIndex the index of the reference map byte
* @param referenceMapByte the value of the reference map byte
* @param referenceMapLabel a label indicating whether this reference map is for a frame or for the registers
*/
@Override
public void logReferenceMapByteBefore(int byteIndex, byte referenceMapByte, String referenceMapLabel) {
if (logStackRootScanning()) {
stackRootScanLogger.logMapByteBefore(byteIndex, referenceMapByte, referenceMapLabel);
}
}
/**
* If {@linkplain Heap#logRootScanning() GC tracing} is enabled, then this method logs the stack slots corresponding to a
* frame or set of set of saved registers that are determined to contain references by a reference map.
*
* @param framePointer the frame pointer. This value should be {@link Pointer#zero()} if the reference map is for a
* set of saved registers.
* @param baseSlotIndex the index of the slot corresponding to bit 0 of {@code referenceMapByte}
* @param referenceMapByte a the reference map byte
*/
@Override
public void logReferenceMapByteAfter(Pointer framePointer, int baseSlotIndex, final byte referenceMapByte) {
if (logStackRootScanning()) {
for (int bitIndex = 0; bitIndex < Bytes.WIDTH; bitIndex++) {
if (((referenceMapByte >>> bitIndex) & 1) != 0) {
final int slotIndex = baseSlotIndex + bitIndex;
stackRootScanLogger.logStackSlot(slotIndex, ttla, framePointer, false);
}
}
}
}
public boolean checkIgnoreCurrentFrame() {
if (ignoreCurrentFrame) {
// Skipping the top frame
ignoreCurrentFrame = false;
return true;
}
return false;
}
@Override
public void setBits(int baseSlotIndex, byte referenceMapByte) {
referenceMap.setBits(baseSlotIndex, referenceMapByte);
}
@Override
public int referenceMapBitIndex(Address slotAddress) {
return referenceMapBitIndex(lowestStackSlot, slotAddress.asPointer());
}
/**
* Updates the reference map bits for a range of slots within a frame.
*
* @param cursor the cursor corresponding to the frame for which the bits are being filled in
* @param slotPointer the pointer to the slot that corresponds to bit 0 in the reference map
* @param refMap an integer containing up to 32 reference map bits for up to 32 successive slots in the frame
* @param numBits the number of bits in the reference map
*/
@Override
public void visitReferenceMapBits(StackFrameCursor cursor, Pointer slotPointer, int refMap, int numBits) {
if (logStackRootScanning()) {
stackRootScanLogger.logSetReferenceMapBits(cursor.sp(), cursor.fp(), slotPointer, refMap, numBits, cursor.targetMethod().regionName());
}
if (!inThisStack(cursor.sp())) {
throw FatalError.unexpected("sp not in this stack");
}
if (!inThisStack(slotPointer)) {
throw FatalError.unexpected("slots not in this stack");
}
if (refMap == 0) {
// nothing to do.
return;
}
if ((refMap & (-1 << numBits)) != 0) {
throw FatalError.unexpected("reference map has extraneous high order bits set");
}
if (verify) {
// look at the contents of the stack and check they are valid refs
for (int i = 0; i < numBits; i++) {
if (((refMap >> i) & 1) == 1) {
Reference ref = slotPointer.getReference(i);
if (Heap.isValidRef(ref)) {
if (logStackRootScanning()) {
stackRootScanLogger.logPrintRef(
slotPointer.plusWords(i),
slotPointer.plusWords(i).minus(cursor.sp()).toInt(),
ref.toOrigin(),
ref.isTagged());
}
} else {
invalidRef(ref, cursor, slotPointer, i);
}
}
}
}
if (prepare) {
// copy the bits into the complete reference map for the stack
int mapBits = refMap;
int slotIndex = referenceMapBitIndex(slotPointer);
int slotEnd = referenceMapBitIndex(slotPointer.plusWords(numBits));
while (slotIndex < slotEnd) {
int rest = slotIndex % Bytes.WIDTH; // number of bits to shift mapBits over
int bits = Bytes.WIDTH - rest; // number of bits from mapBits to use
int byteIndex = UnsignedMath.divide(slotIndex, Bytes.WIDTH);
byte prev = referenceMap.getByte(byteIndex);
prev |= mapBits << rest;
referenceMap.setByte(byteIndex, prev);
slotIndex += bits;
mapBits >>>= bits;
}
}
}
@NEVER_INLINE
private void invalidRef(Reference ref, StackFrameCursor cursor, Pointer slotPointer, int slotIndex) {
StackRootScanLogger.printRef(slotPointer.plusWords(slotIndex), slotPointer.plusWords(slotIndex).minus(cursor.sp()).toInt(), ref.toOrigin(), ref.isTagged(), false);
Log.print("invalid ref ### [SRSCount: ");
Log.print(SRSCount.get());
Log.print("] ");
final Pointer ip = cursor.ipAsPointer();
Throw.logFrame(null, cursor.targetMethod(), ip);
throw FatalError.unexpected("invalid ref");
}
private boolean inThisStack(Pointer pointer) {
return pointer.greaterEqual(lowestStackSlot);
}
/**
* Walks the stack of the current thread from the current
* instruction pointer, stack pointer, and frame pointer, verifying the reference map
* for each stack frame by using the {@link Heap#isValidRef(Reference)}
* heuristic.
*/
public static void verifyReferenceMapsForThisThread() {
VmThread current = VmThread.current();
current.stackReferenceMapVerifier().verifyReferenceMaps0(current, CodePointer.from(here()), getCpuStackPointer(), getCpuFramePointer());
}
/**
* Walks the stack of a given thread from a specified frame, verifying the reference map
* for each stack frame by using the {@link Heap#isValidRef(Reference)}
* heuristic.
*/
public static void verifyReferenceMaps(VmThread thread, CodePointer ip, Pointer sp, Pointer fp) {
thread.stackReferenceMapVerifier().verifyReferenceMaps0(thread, ip, sp, fp);
}
private void verifyReferenceMaps0(VmThread thread, CodePointer ip, Pointer sp, Pointer fp) {
Pointer tla = thread.tla();
initRefMapFields(tla);
boolean lockDisabledSafepoints = logStackRootScanStart(sp, HIGHEST_STACK_SLOT_ADDRESS.load(tla), thread);
thread.stackDumpStackFrameWalker().verifyReferenceMap(ip.toPointer(), sp, fp, this);
logStackRootScanEnd(lockDisabledSafepoints);
}
/*
* Logging.
*/
/**
* Stack root scan logger instance.
*/
public static final StackRootScanLogger stackRootScanLogger = new StackRootScanLogger();
/**
* Stack root scan logger.
* Encapsulates all the loggable operations related to stack root scanning. (and there are a lot).
* This is by far the most complex logger in the system and was the most difficult to convert
* from the previous trace-only mode. It was necessary to store several {@link Reference} valued
* objects in the log in order to accurately preserve the tracing.
*/
@HOSTED_ONLY
@VMLoggerInterface
private interface StackRootScanLoggerInterface {
// pack 8/9th args to stay in 8 arg limit
void start(
@VMLogParam(name = "count") int count,
@VMLogParam(name = "prepare") boolean prepare,
@VMLogParam(name = "stackPointer") Pointer stackPointer,
@VMLogParam(name = "highestStackSlot") Pointer highestStackSlot,
@VMLogParam(name = "lowestStackSlot") Pointer lowestStackSlot,
@VMLogParam(name = "vmThread") VmThread vmThread,
@VMLogParam(name = "highestStackSlotReferenceMapBitIndex") int highestStackSlotReferenceMapBitIndex,
// @VMLogParam(name = "stackPointerReferenceMapBitIndex") int stackPointerReferenceMapBitIndex,
// @VMLogParam(name = "lowestStackSlotReferenceMapBitIndex") int lowestStackSlotReferenceMapBitIndex);
@VMLogParam(name = "stackAndLowestStackSlotReferenceMapBitIndex") long stackAndLowestStackSlotReferenceMapBitIndex);
void startThreadLocals();
void scanThread(
@VMLogParam(name = "vmThread") VmThread vmThread);
void referenceThreadLocal(
@VMLogParam(name = "index") int index,
@VMLogParam(name = "address") Pointer address,
@VMLogParam(name = "value") Word value,
@VMLogParam(name = "name") String name,
@VMLogParam(name = "categorySuffix") String categorySuffix);
void threadSlotRange(
@VMLogParam(name = "highestSlot") Pointer highestSlot,
@VMLogParam(name = "lowestActiveSlot") Pointer lowestActiveSlot,
@VMLogParam(name = "lowestSlot") Pointer lowestSlot);
void prepare(
@VMLogParam(name = "prepare") boolean prepare,
@VMLogParam(name = "targetMethod") TargetMethod targetMethod,
@VMLogParam(name = "safepointIndex") int safepointIndex,
@VMLogParam(name = "refmapFramePointer") Pointer refmapFramePointer,
@VMLogParam(name = "label") String label,
@VMLogParam(name = "refmapFramePointerBitIndex") int refmapFramePointerBitIndex,
@VMLogParam(name = "ttla") Pointer ttla);
void printRef(
@VMLogParam(name = "refPointer") Pointer refPointer,
@VMLogParam(name = "spOffset") int spOffset,
@VMLogParam(name = "refOrigin") Pointer refOrigin,
@VMLogParam(name = "isTagged") boolean isTagged);
void registerState(
@VMLogParam(name = "reg") CiRegister reg);
void parameter(
@VMLogParam(name = "index") int index,
@VMLogParam(name = "parameter") TypeDescriptor parameter);
void receiver(
@VMLogParam(name = "receiver") TypeDescriptor receiver);
void stackSlot(
@VMLogParam(name = "slotIndex") int slotIndex,
@VMLogParam(name = "tla") Pointer tla,
@VMLogParam(name = "framePointer") Pointer framePointer,
@VMLogParam(name = "checkTagging") boolean checkTagging);
void clearedRefMapIndexes(
@VMLogParam(name = "lowestBitIndex") int lowestBitIndex,
@VMLogParam(name = "highestBitIndex") int highestBitIndex);
void complete(
@VMLogParam(name = "vmThread") VmThread vmThread,
@VMLogParam(name = "highestSlot") Pointer highestSlot,
@VMLogParam(name = "highestSlotBitIndex") int highestSlotBitIndex,
@VMLogParam(name = "stackPointer") Pointer stackPointer,
@VMLogParam(name = "stackPointerBitIndex") int stackPointerSlotBitIndex,
@VMLogParam(name = "lowestSlot") Pointer lowestSlot,
@VMLogParam(name = "lowestSlotBitIndex") int lowestSlotBitIndex);
void emptyMap(
@VMLogParam(name = "vmThread") VmThread vmThread);
void finalizeMaps(
@VMLogParam(name = "interval") Interval interval,
@VMLogParam(name = "helper") ReferenceMapEditorLogHelper helper);
void safepoint(
@VMLogParam(name = "helper") ReferenceMapEditorLogHelper helper,
@VMLogParam(name = "interpreter") ReferenceMapInterpreter interpreter,
@VMLogParam(name = "bci") int bci,
@VMLogParam(name = "safePointIndex") int safePointIndex);
void mapByteBefore(
@VMLogParam(name = "byteIndex") int byteIndex,
@VMLogParam(name = "referenceMapByte") byte referenceMapByte,
@VMLogParam(name = "referenceMapLabel") String referenceMapLabel);
void setReferenceMapBits(
@VMLogParam(name = "sp") Pointer sp,
@VMLogParam(name = "fp") Pointer fp,
@VMLogParam(name = "slotPointer") Pointer slotPointer,
@VMLogParam(name = "refMapBits") int refMapBits,
@VMLogParam(name = "numBits") int numBits,
@VMLogParam(name = "description") String description);
}
/*
* Methods to access typed objects stored in untyped form in the log (at present).
*/
@INTRINSIC(UNSAFE_CAST)
private static native TypeDescriptor asTypeDescriptor(Object arg);
private static TypeDescriptor toTypeDescriptor(Record r, int argNum) {
return asTypeDescriptor(VMLogger.toObject(r, argNum));
}
// This could be stored with as its "number" save that it is currently hard to convert back.
@INTRINSIC(UNSAFE_CAST)
private static native CiRegister asCiRegister(Object arg);
private static CiRegister toCiRegister(Record r, int argNum) {
return asCiRegister(VMLogger.toObject(r, argNum));
}
@INTRINSIC(UNSAFE_CAST)
private static native ReferenceMapEditorLogHelper asReferenceMapEditorLogHelper(Object arg);
private static ReferenceMapEditorLogHelper toReferenceMapEditorLogHelper(Record r, int argNum) {
return asReferenceMapEditorLogHelper(VMLogger.toObject(r, argNum));
}
@INTRINSIC(UNSAFE_CAST)
private static native ReferenceMapInterpreter asReferenceMapInterpreter(Object arg);
private static ReferenceMapInterpreter toReferenceMapInterpreter(Record r, int argNum) {
return asReferenceMapInterpreter(VMLogger.toObject(r, argNum));
}
public static final class StackRootScanLogger extends StackRootScanLoggerAuto {
StackRootScanLogger() {
super("SRS", "stack root scanning.");
}
@INLINE
void logStart(int count, boolean prepare, Pointer stackPointer, Pointer highestStackSlot, Pointer lowestStackSlot, VmThread vmThread,
int highestStackSlotReferenceMapBitIndex, int stackPointerReferenceMapBitIndex, int lowestStackSlotReferenceMapBitIndex) {
// would exceed 8 arg limit without packing.
log(Operation.Start.ordinal(), intArg(count), booleanArg(prepare), stackPointer, highestStackSlot, lowestStackSlot,
vmThreadArg(vmThread),
intArg(highestStackSlotReferenceMapBitIndex),
twoIntArgs(stackPointerReferenceMapBitIndex, lowestStackSlotReferenceMapBitIndex));
}
@Override
public void checkOptions() {
super.checkOptions();
checkDominantLoggerOptions(Heap.rootScanLogger);
}
@Override
protected void traceStart(int count, boolean prepare, Pointer stackPointer, Pointer highestStackSlot,
Pointer lowestStackSlot, VmThread vmThread, int highestStackSlotReferenceMapBitIndex,
long stackAndLowestStackSlotReferenceMapBitIndex) {
int stackPointerReferenceMapBitIndex = toIntArg1(stackAndLowestStackSlotReferenceMapBitIndex);
int lowestStackSlotReferenceMapBitIndex = toIntArg2(stackAndLowestStackSlotReferenceMapBitIndex);
Log.print('[');
Log.print(count);
Log.print(prepare ? "] Preparing" : "] Verifying");
Log.print(" stack reference map for thread ");
Log.printThread(vmThread, false);
Log.println(":");
Log.print(" Highest slot: ");
Log.print(highestStackSlot);
Log.print(" [index=");
Log.print(highestStackSlotReferenceMapBitIndex);
Log.println("]");
Log.print(" Lowest active slot: ");
Log.print(stackPointer);
Log.print(" [index=");
Log.print(stackPointerReferenceMapBitIndex);
Log.println("]");
Log.print(" Lowest slot: ");
Log.print(lowestStackSlot);
Log.print(" [index=");
Log.print(lowestStackSlotReferenceMapBitIndex);
Log.println("]");
Log.print(" Current thread is ");
Log.printCurrentThread(true);
}
@Override
protected void traceEmptyMap(VmThread vmThread) {
Log.print("Empty stack reference map for thread ");
Log.printThread(vmThread, true);
}
@Override
protected void traceComplete(VmThread vmThread, Pointer highestSlot, int highestSlotBitIndex, Pointer stackPointer,
int stackPointerBitIndex, Pointer lowestSlot, int lowestSlotBitIndex) {
Log.print("Completing preparation of stack reference map for thread ");
Log.printThread(vmThread, false);
Log.println(":");
Log.print(" Highest slot: ");
Log.print(highestSlot);
Log.print(" [index=");
Log.print(highestSlotBitIndex);
Log.println("]");
Log.print(" Lowest active slot: ");
Log.print(stackPointer);
Log.print(" [index=");
Log.print(stackPointerBitIndex);
Log.println("]");
Log.print(" Lowest slot: ");
Log.print(lowestSlot);
Log.print(" [index=");
Log.print(lowestSlotBitIndex);
Log.println("]");
Log.print(" Current thread is ");
Log.printCurrentThread(true);
}
@Override
protected void traceParameter(int index, TypeDescriptor parameter) {
Log.print(" parameter ");
Log.print(index);
Log.print(", type: ");
Log.println(parameter.string);
}
@Override
protected void traceSafepoint(ReferenceMapEditorLogHelper helper, ReferenceMapInterpreter interpreter, int bci, int safePointIndex) {
// Tracing this is complex and compiler specific, so we call back
helper.traceSafepoint(interpreter, bci, safePointIndex);
}
@Override
protected void tracePrintRef(Pointer refPointer, int spOffset, Pointer refOrigin, boolean isTagged) {
printRef(refPointer, spOffset, refOrigin, isTagged, true);
}
@Override
protected void tracePrepare(boolean prepare, TargetMethod targetMethod, int safepointIndex, Pointer refmapFramePointer,
String label, int refmapFramePointerBitIndex, Pointer ttla) {
Log.print(prepare ? " Preparing" : " Verifying");
Log.print(" reference map for ");
Log.print(label);
Log.print(" of ");
Log.printMethod(targetMethod, false);
Log.print(" +");
Log.println(targetMethod);
Log.print(" Stop index: ");
Log.println(safepointIndex);
if (!refmapFramePointer.isZero()) {
Log.print(" Frame pointer: ");
printSlot(refmapFramePointerBitIndex, ttla, Pointer.zero(), false);
Log.println();
}
}
@Override
protected void traceStartThreadLocals() {
Log.println(" Thread locals:");
}
@Override
protected void traceScanThread(VmThread vmThread) {
Log.print("Scanning thread locals and stack for thread ");
Log.printThread(vmThread, false);
Log.print(":");
}
@Override
protected void traceReferenceThreadLocal(int index, Pointer address, Word value, String name, String categorySuffix) {
Log.print(" index=");
Log.print(index);
Log.print(", address=");
Log.print(address);
Log.print(", value=");
Log.print(value);
Log.print(", name=");
Log.print(name);
Log.println(categorySuffix);
}
@Override
protected void traceThreadSlotRange(Pointer highestSlot, Pointer lowestActiveSlot, Pointer lowestSlot) {
if (highestSlot.isZero()) {
Log.print("No Java stack frames");
} else {
Log.print(" Highest slot: ");
Log.println(highestSlot);
Log.print(" Lowest active slot: ");
Log.println(lowestActiveSlot);
Log.print(" Lowest slot: ");
Log.println(lowestSlot);
}
}
@Override
protected void traceRegisterState(CiRegister reg) {
Log.print(" register: ");
Log.println(reg.name);
}
@Override
protected void traceReceiver(TypeDescriptor receiver) {
Log.print(" receiver, type: ");
Log.println(receiver.string);
}
@Override
protected void traceStackSlot(int slotIndex, Pointer tla, Pointer framePointer, boolean checkTagging) {
Log.print(" Slot: ");
printSlot(slotIndex, tla, framePointer, checkTagging);
Log.println();
}
@Override
protected void traceClearedRefMapIndexes(int lowestBitIndex, int highestBitIndex) {
Log.print("Cleared refmap indexes [");
Log.print(lowestBitIndex);
Log.print(" .. ");
Log.print(highestBitIndex);
Log.println("]");
}
@Override
protected void traceFinalizeMaps(Interval interval, ReferenceMapEditorLogHelper helper) {
Log.printCurrentThread(false);
Log.print(": ");
Log.print(interval == Interval.BEGIN ? "Finalizing " : "Finalized ");
Log.print(helper.compilerName()); Log.print(" reference maps for ");
Log.printMethod(helper.targetMethod().classMethodActor, true);
}
@Override
protected void traceMapByteBefore(int byteIndex, byte referenceMapByte, String referenceMapLabel) {
Log.print(" ");
Log.print(referenceMapLabel);
Log.print(" map byte index: ");
Log.println(byteIndex);
Log.print(" ");
Log.print(referenceMapLabel);
Log.print(" map byte: ");
Log.println(referenceMapByte);
}
@Override
protected void traceSetReferenceMapBits(Pointer sp, Pointer fp, Pointer slotPointer, int refMapBits, int numBits, String description) {
Log.print(" setReferenceMapBits: sp = ");
Log.print(sp);
Log.print(" fp = ");
Log.print(fp);
Log.print(", slots @ ");
Log.print(slotPointer);
Log.print(", bits = ");
for (int i = 0; i < numBits; i++) {
Log.print((refMapBits >>> i) & 1);
}
Log.print(", description = ");
Log.println(description);
}
private static void printRef(Pointer refStackPointer, int spOffset, Pointer refOrigin, boolean tagged, boolean valid) {
Log.print(" ref @ ");
Log.print(refStackPointer);
Log.print(" [sp + ");
Log.print(spOffset);
Log.print("] = ");
Log.print(refOrigin);
if (tagged) {
Log.print(" tagged");
}
Log.print(valid ? " ok\n" : " (invalid)\n");
}
private static void printSlot(int slotIndex, Pointer tla, Pointer framePointer, boolean checkTagging) {
Pointer slotAddress = slotAddress(slotIndex, tla);
Pointer referenceMap = STACK_REFERENCE_MAP.load(tla);
Log.print("index=");
Log.print(slotIndex);
if (!framePointer.isZero()) {
final int offset = slotAddress.minus(framePointer).toInt();
if (offset >= 0) {
Log.print(", fp+");
} else {
Log.print(", fp");
}
Log.print(offset);
}
Log.print(", address=");
Log.print(slotAddress);
Log.print(", value=");
final Word value = slotAddress.readWord(0);
Log.print(value);
if (checkTagging && Reference.fromOrigin(value.asPointer()).isTagged()) {
Log.print(" (tagged)");
}
if (slotAddress.lessThan(referenceMap)) {
Pointer etla = ETLA.load(tla);
Pointer dtla = DTLA.load(tla);
Pointer ttla = TTLA.load(tla);
if (slotAddress.greaterEqual(dtla)) {
Log.print(", name=");
int vmThreadLocalIndex = slotAddress.minus(dtla).dividedBy(Word.size()).toInt();
Log.print(values().get(vmThreadLocalIndex).name);
} else if (slotAddress.greaterEqual(etla)) {
Log.print(", name=");
int vmThreadLocalIndex = slotAddress.minus(etla).dividedBy(Word.size()).toInt();
Log.print(values().get(vmThreadLocalIndex).name);
} else if (slotAddress.greaterEqual(ttla)) {
Log.print(", name=");
int vmThreadLocalIndex = slotAddress.minus(ttla).dividedBy(Word.size()).toInt();
Log.print(values().get(vmThreadLocalIndex).name);
}
}
}
}
// START GENERATED CODE
private static abstract class StackRootScanLoggerAuto extends com.sun.max.vm.log.VMLogger {
public enum Operation {
ClearedRefMapIndexes, Complete, EmptyMap,
FinalizeMaps, MapByteBefore, Parameter, Prepare,
PrintRef, Receiver, ReferenceThreadLocal, RegisterState,
Safepoint, ScanThread, SetReferenceMapBits, StackSlot,
Start, StartThreadLocals, ThreadSlotRange;
@SuppressWarnings("hiding")
public static final Operation[] VALUES = values();
}
private static final int[] REFMAPS = new int[] {0x0, 0x0, 0x0, 0x2, 0x4, 0x2, 0x12, 0x0, 0x1, 0x18, 0x1, 0x3, 0x0, 0x20,
0x0, 0x0, 0x0, 0x0};
protected StackRootScanLoggerAuto(String name, String optionDescription) {
super(name, Operation.VALUES.length, optionDescription, REFMAPS);
}
@Override
public String operationName(int opCode) {
return Operation.VALUES[opCode].name();
}
@INLINE
public final void logClearedRefMapIndexes(int lowestBitIndex, int highestBitIndex) {
log(Operation.ClearedRefMapIndexes.ordinal(), intArg(lowestBitIndex), intArg(highestBitIndex));
}
protected abstract void traceClearedRefMapIndexes(int lowestBitIndex, int highestBitIndex);
@INLINE
public final void logComplete(VmThread vmThread, Pointer highestSlot, int highestSlotBitIndex, Pointer stackPointer, int stackPointerBitIndex,
Pointer lowestSlot, int lowestSlotBitIndex) {
log(Operation.Complete.ordinal(), vmThreadArg(vmThread), highestSlot, intArg(highestSlotBitIndex), stackPointer, intArg(stackPointerBitIndex),
lowestSlot, intArg(lowestSlotBitIndex));
}
protected abstract void traceComplete(VmThread vmThread, Pointer highestSlot, int highestSlotBitIndex, Pointer stackPointer, int stackPointerBitIndex,
Pointer lowestSlot, int lowestSlotBitIndex);
@INLINE
public final void logEmptyMap(VmThread vmThread) {
log(Operation.EmptyMap.ordinal(), vmThreadArg(vmThread));
}
protected abstract void traceEmptyMap(VmThread vmThread);
@INLINE
public final void logFinalizeMaps(Interval interval, ReferenceMapEditorLogHelper helper) {
log(Operation.FinalizeMaps.ordinal(), intervalArg(interval), objectArg(helper));
}
protected abstract void traceFinalizeMaps(Interval interval, ReferenceMapEditorLogHelper helper);
@INLINE
public final void logMapByteBefore(int byteIndex, byte referenceMapByte, String referenceMapLabel) {
log(Operation.MapByteBefore.ordinal(), intArg(byteIndex), objectArg(referenceMapByte), objectArg(referenceMapLabel));
}
protected abstract void traceMapByteBefore(int byteIndex, byte referenceMapByte, String referenceMapLabel);
@INLINE
public final void logParameter(int index, TypeDescriptor parameter) {
log(Operation.Parameter.ordinal(), intArg(index), objectArg(parameter));
}
protected abstract void traceParameter(int index, TypeDescriptor parameter);
@INLINE
public final void logPrepare(boolean prepare, TargetMethod targetMethod, int safepointIndex, Pointer refmapFramePointer, String label,
int refmapFramePointerBitIndex, Pointer ttla) {
log(Operation.Prepare.ordinal(), booleanArg(prepare), objectArg(targetMethod), intArg(safepointIndex), refmapFramePointer, objectArg(label),
intArg(refmapFramePointerBitIndex), ttla);
}
protected abstract void tracePrepare(boolean prepare, TargetMethod targetMethod, int safepointIndex, Pointer refmapFramePointer, String label,
int refmapFramePointerBitIndex, Pointer ttla);
@INLINE
public final void logPrintRef(Pointer refPointer, int spOffset, Pointer refOrigin, boolean isTagged) {
log(Operation.PrintRef.ordinal(), refPointer, intArg(spOffset), refOrigin, booleanArg(isTagged));
}
protected abstract void tracePrintRef(Pointer refPointer, int spOffset, Pointer refOrigin, boolean isTagged);
@INLINE
public final void logReceiver(TypeDescriptor receiver) {
log(Operation.Receiver.ordinal(), objectArg(receiver));
}
protected abstract void traceReceiver(TypeDescriptor receiver);
@INLINE
public final void logReferenceThreadLocal(int index, Pointer address, Word value, String name, String categorySuffix) {
log(Operation.ReferenceThreadLocal.ordinal(), intArg(index), address, value, objectArg(name), objectArg(categorySuffix));
}
protected abstract void traceReferenceThreadLocal(int index, Pointer address, Word value, String name, String categorySuffix);
@INLINE
public final void logRegisterState(CiRegister reg) {
log(Operation.RegisterState.ordinal(), objectArg(reg));
}
protected abstract void traceRegisterState(CiRegister reg);
@INLINE
public final void logSafepoint(ReferenceMapEditorLogHelper helper, ReferenceMapInterpreter interpreter, int bci, int safePointIndex) {
log(Operation.Safepoint.ordinal(), objectArg(helper), objectArg(interpreter), intArg(bci), intArg(safePointIndex));
}
protected abstract void traceSafepoint(ReferenceMapEditorLogHelper helper, ReferenceMapInterpreter interpreter, int bci, int safePointIndex);
@INLINE
public final void logScanThread(VmThread vmThread) {
log(Operation.ScanThread.ordinal(), vmThreadArg(vmThread));
}
protected abstract void traceScanThread(VmThread vmThread);
@INLINE
public final void logSetReferenceMapBits(Pointer sp, Pointer fp, Pointer slotPointer, int refMapBits, int numBits,
String description) {
log(Operation.SetReferenceMapBits.ordinal(), sp, fp, slotPointer, intArg(refMapBits), intArg(numBits),
objectArg(description));
}
protected abstract void traceSetReferenceMapBits(Pointer sp, Pointer fp, Pointer slotPointer, int refMapBits, int numBits,
String description);
@INLINE
public final void logStackSlot(int slotIndex, Pointer tla, Pointer framePointer, boolean checkTagging) {
log(Operation.StackSlot.ordinal(), intArg(slotIndex), tla, framePointer, booleanArg(checkTagging));
}
protected abstract void traceStackSlot(int slotIndex, Pointer tla, Pointer framePointer, boolean checkTagging);
@INLINE
public final void logStart(int count, boolean prepare, Pointer stackPointer, Pointer highestStackSlot, Pointer lowestStackSlot,
VmThread vmThread, int highestStackSlotReferenceMapBitIndex, long stackAndLowestStackSlotReferenceMapBitIndex) {
log(Operation.Start.ordinal(), intArg(count), booleanArg(prepare), stackPointer, highestStackSlot, lowestStackSlot,
vmThreadArg(vmThread), intArg(highestStackSlotReferenceMapBitIndex), longArg(stackAndLowestStackSlotReferenceMapBitIndex));
}
protected abstract void traceStart(int count, boolean prepare, Pointer stackPointer, Pointer highestStackSlot, Pointer lowestStackSlot,
VmThread vmThread, int highestStackSlotReferenceMapBitIndex, long stackAndLowestStackSlotReferenceMapBitIndex);
@INLINE
public final void logStartThreadLocals() {
log(Operation.StartThreadLocals.ordinal());
}
protected abstract void traceStartThreadLocals();
@INLINE
public final void logThreadSlotRange(Pointer highestSlot, Pointer lowestActiveSlot, Pointer lowestSlot) {
log(Operation.ThreadSlotRange.ordinal(), highestSlot, lowestActiveSlot, lowestSlot);
}
protected abstract void traceThreadSlotRange(Pointer highestSlot, Pointer lowestActiveSlot, Pointer lowestSlot);
@Override
protected void trace(Record r) {
switch (r.getOperation()) {
case 0: { //ClearedRefMapIndexes
traceClearedRefMapIndexes(toInt(r, 1), toInt(r, 2));
break;
}
case 1: { //Complete
traceComplete(toVmThread(r, 1), toPointer(r, 2), toInt(r, 3), toPointer(r, 4), toInt(r, 5), toPointer(r, 6), toInt(r, 7));
break;
}
case 2: { //EmptyMap
traceEmptyMap(toVmThread(r, 1));
break;
}
case 3: { //FinalizeMaps
traceFinalizeMaps(toInterval(r, 1), toReferenceMapEditorLogHelper(r, 2));
break;
}
case 4: { //MapByteBefore
traceMapByteBefore(toInt(r, 1), toByte(r, 2), toString(r, 3));
break;
}
case 5: { //Parameter
traceParameter(toInt(r, 1), toTypeDescriptor(r, 2));
break;
}
case 6: { //Prepare
tracePrepare(toBoolean(r, 1), toTargetMethod(r, 2), toInt(r, 3), toPointer(r, 4), toString(r, 5), toInt(r, 6), toPointer(r, 7));
break;
}
case 7: { //PrintRef
tracePrintRef(toPointer(r, 1), toInt(r, 2), toPointer(r, 3), toBoolean(r, 4));
break;
}
case 8: { //Receiver
traceReceiver(toTypeDescriptor(r, 1));
break;
}
case 9: { //ReferenceThreadLocal
traceReferenceThreadLocal(toInt(r, 1), toPointer(r, 2), toWord(r, 3), toString(r, 4), toString(r, 5));
break;
}
case 10: { //RegisterState
traceRegisterState(toCiRegister(r, 1));
break;
}
case 11: { //Safepoint
traceSafepoint(toReferenceMapEditorLogHelper(r, 1), toReferenceMapInterpreter(r, 2), toInt(r, 3), toInt(r, 4));
break;
}
case 12: { //ScanThread
traceScanThread(toVmThread(r, 1));
break;
}
case 13: { //SetReferenceMapBits
traceSetReferenceMapBits(toPointer(r, 1), toPointer(r, 2), toPointer(r, 3), toInt(r, 4), toInt(r, 5), toString(r, 6));
break;
}
case 14: { //StackSlot
traceStackSlot(toInt(r, 1), toPointer(r, 2), toPointer(r, 3), toBoolean(r, 4));
break;
}
case 15: { //Start
traceStart(toInt(r, 1), toBoolean(r, 2), toPointer(r, 3), toPointer(r, 4), toPointer(r, 5), toVmThread(r, 6), toInt(r, 7), toLong(r, 8));
break;
}
case 16: { //StartThreadLocals
traceStartThreadLocals();
break;
}
case 17: { //ThreadSlotRange
traceThreadSlotRange(toPointer(r, 1), toPointer(r, 2), toPointer(r, 3));
break;
}
}
}
}
// END GENERATED CODE
}