/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt.runtimesupport.ppc; import static org.jikesrvm.compilers.opt.runtimesupport.ppc.OptGCMapIteratorConstants.LAST_GCMAP_REG; import static org.jikesrvm.ppc.RegisterConstants.FIRST_SCRATCH_GPR; import static org.jikesrvm.ppc.RegisterConstants.FIRST_VOLATILE_GPR; import static org.jikesrvm.ppc.RegisterConstants.LAST_SCRATCH_GPR; import static org.jikesrvm.ppc.RegisterConstants.LAST_VOLATILE_GPR; import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS; import org.jikesrvm.VM; import org.jikesrvm.compilers.opt.runtimesupport.OptGenericGCMapIterator; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.AddressArray; /** * An instance of this class provides iteration across the references * represented by a frame built by the OPT compiler. * <p> * The architecture-specific version of the GC Map iterator. It inherits * its architecture-independent code from OptGenericGCMapIterator. * This version is for the PowerPC. */ @Uninterruptible public final class OptGCMapIterator extends OptGenericGCMapIterator { private static final boolean DEBUG = false; public OptGCMapIterator(AddressArray registerLocations) { super(registerLocations); } @Override protected void updateLocateRegisters() { // HIGH MEMORY // // +------------------+ // | NVolGPR[n] | // | ... | k == info.getFirstNonVolatileGPR() // | NVolGPR[k] | <-- info.getUnsignedNonVolatileOffset() // +------------------+ // | ScratchGPR[LAST]| // | ... | only SaveVolatile Frames // | ScratchGPR[FIRST]| // +------------------+ // | VolGPR[LAST] | // | ... | only SaveVolatile Frames // | VolGPR[FIRST] | // +------------------+ // // LOW MEMORY int frameOffset = compiledMethod.getUnsignedNonVolatileOffset(); if (frameOffset >= 0) { // get to the nonVol area Address nonVolArea = framePtr.plus(frameOffset); // update non-volatiles that were saved int first = compiledMethod.getFirstNonVolatileGPR(); if (first >= 0) { // move to the beginning of the save area for nonvolatiles Address location = nonVolArea; for (int i = first; i <= LAST_GCMAP_REG; i++) { registerLocations.set(i, location); location = location.plus(BYTES_IN_ADDRESS); } } // update volatiles if needed if (compiledMethod.isSaveVolatile()) { // move to the beginning of the save area for volatiles Address location = nonVolArea.minus(SAVE_VOL_SIZE); // Walk the saved volatiles, updating registerLocations array for (int i = FIRST_VOLATILE_GPR.value(); i <= LAST_VOLATILE_GPR.value(); i++) { registerLocations.set(i, location); location = location.plus(BYTES_IN_ADDRESS); } // Walk the saved scratch, updating registerLocations array for (int i = FIRST_SCRATCH_GPR.value(); i <= LAST_SCRATCH_GPR.value(); i++) { registerLocations.set(i, location); location = location.plus(BYTES_IN_ADDRESS); } } } } @Override public Address getStackLocation(Address framePtr, int offset) { return framePtr.plus(offset); } /** * Get address of the first spill location for the frame ptr. * @return the first spill location */ @Override public Address getFirstSpillLoc() { return framePtr.plus(SPILL_DISTANCE_FROM_FP); } /** * Get address of the last spill location for the frame ptr. * * @return the last spill location, if no spills occur, we return the * first spill location */ @Override public Address getLastSpillLoc() { if (DEBUG) { VM.sysWriteln(); VM.sysWrite(" unsigendNVOffset: "); VM.sysWrite(compiledMethod.getUnsignedNonVolatileOffset()); VM.sysWrite("\t isSaveVolatile: "); if (compiledMethod.isSaveVolatile()) { VM.sysWriteln("true"); } else { VM.sysWriteln("false"); } VM.sysWrite("LAST_VOLATILE_GPR: "); VM.sysWrite(LAST_VOLATILE_GPR.toString()); VM.sysWrite("\tFIRST_VOLATILE_GPR: "); VM.sysWriteln(LAST_VOLATILE_GPR.toString()); VM.sysWrite("LAST_SCRATCH_GPR: "); VM.sysWrite(LAST_SCRATCH_GPR.toString()); VM.sysWrite("\tFIRST_SCRATCH_GPR: "); VM.sysWriteln(LAST_SCRATCH_GPR.toString()); VM.sysWrite("SAVE_VOL_SIZE: "); VM.sysWrite(SAVE_VOL_SIZE); VM.sysWriteln(); } // This computation will include some locations that are not technically // spill locations. We do this because we currently do not record // enough info in the OptCompiledMethod object (the one that is available // at GC time) to distinguish the lower part of the spill. Address firstSpill = getFirstSpillLoc(); Address lastSpill; int nonVolOffset = compiledMethod.getUnsignedNonVolatileOffset(); if (nonVolOffset != 0) { if (compiledMethod.isSaveVolatile()) { lastSpill = framePtr.plus(nonVolOffset - BYTES_IN_ADDRESS - SAVE_VOL_SIZE); } else { lastSpill = framePtr.plus(nonVolOffset - BYTES_IN_ADDRESS); } // If the above computation is less than firstSpill, there are no spills if (lastSpill.LT(firstSpill)) { lastSpill = firstSpill; } } else { // If nonVolOffset = 0, there are no spills lastSpill = firstSpill; } return lastSpill; } static final int SPILL_DISTANCE_FROM_FP = 3 * BYTES_IN_ADDRESS; static final int SAVE_VOL_SIZE = BYTES_IN_ADDRESS * ((LAST_VOLATILE_GPR.value() - FIRST_VOLATILE_GPR.value() + 1) + (LAST_SCRATCH_GPR.value() - FIRST_SCRATCH_GPR.value() + 1)); }