/*
* 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.ia32;
import static org.jikesrvm.ia32.RegisterConstants.NONVOLATILE_GPRS;
import static org.jikesrvm.ia32.RegisterConstants.NUM_NONVOLATILE_GPRS;
import static org.jikesrvm.ia32.RegisterConstants.NUM_VOLATILE_GPRS;
import static org.jikesrvm.ia32.RegisterConstants.VOLATILE_GPRS;
import static org.jikesrvm.ia32.StackframeLayoutConstants.OPT_SAVE_VOLATILE_TOTAL_SIZE;
import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_BODY_OFFSET;
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 IA32.
*/
@Uninterruptible
public final class OptGCMapIterator extends OptGenericGCMapIterator {
private static final boolean DEBUG = false;
public OptGCMapIterator(AddressArray registerLocations) {
super(registerLocations);
}
/**
* If any non-volatile GPRs were saved by the method being processed
* then update the registerLocations array with the locations where the
* registers were saved. Also, check for special methods that also
* save the volatile GPRs.
*/
@Override
protected void updateLocateRegisters() {
// HIGH MEMORY
//
// +---------------+ |
// FP-> | saved FP | <-- this frame's caller's frame |
// +---------------+ |
// | cmid | <-- this frame's compiledmethod id |
// +---------------+ |
// | | |
// | Spill Area | <-- spills and other method-specific |
// | ... | compiler-managed storage |
// +---------------+ |
// | Saved FP | only SaveVolatile Frames |
// | State | |
// +---------------+ |
// | VolGPR[0] |
// | ... | only SaveVolatile Frames
// | VolGPR[n] |
// +---------------+
// | NVolGPR[k] | <-- cm.getUnsignedNonVolatileOffset()
// | ... | k == cm.getFirstNonVolatileGPR()
// | NVolGPR[n] |
// +---------------+
//
// LOW MEMORY
int frameOffset = compiledMethod.getUnsignedNonVolatileOffset();
if (frameOffset >= 0) {
// get to the non vol area
Address nonVolArea = framePtr.minus(frameOffset);
// update non-volatiles
int first = compiledMethod.getFirstNonVolatileGPR();
if (first >= 0) {
// move to the beginning of the nonVol area
Address location = nonVolArea;
for (int i = first; i < NUM_NONVOLATILE_GPRS; i++) {
// determine what register index corresponds to this location
int registerIndex = NONVOLATILE_GPRS[i].value();
registerLocations.set(registerIndex, location);
if (DEBUG) {
VM.sysWrite("UpdateRegisterLocations: Register ");
VM.sysWrite(registerIndex);
VM.sysWrite(" to Location ");
VM.sysWrite(location);
VM.sysWriteln();
}
location = location.minus(BYTES_IN_ADDRESS);
}
}
// update volatiles if needed
if (compiledMethod.isSaveVolatile()) {
// move to the beginning of the nonVol area
Address location = nonVolArea.plus(BYTES_IN_ADDRESS * NUM_VOLATILE_GPRS);
for (int i = 0; i < NUM_VOLATILE_GPRS; i++) {
// determine what register index corresponds to this location
int registerIndex = VOLATILE_GPRS[i].value();
registerLocations.set(registerIndex, location);
if (DEBUG) {
VM.sysWrite("UpdateRegisterLocations: Register ");
VM.sysWrite(registerIndex);
VM.sysWrite(" to Location ");
VM.sysWrite(location);
VM.sysWriteln();
}
location = location.minus(BYTES_IN_ADDRESS);
}
}
}
}
@Override
public Address getStackLocation(Address framePtr, int offset) {
return framePtr.minus(offset);
}
/**
* Get address of the first spill location for the given frame ptr
* @return the first spill location
*/
@Override
public Address getFirstSpillLoc() {
return framePtr.plus(STACKFRAME_BODY_OFFSET);
}
/**
* Get address of the last spill location for the given frame ptr
* @return the last spill location
*/
@Override
public Address getLastSpillLoc() {
if (compiledMethod.isSaveVolatile()) {
return framePtr.minus(compiledMethod.getUnsignedNonVolatileOffset() - BYTES_IN_ADDRESS - OPT_SAVE_VOLATILE_TOTAL_SIZE);
} else {
return framePtr.minus(compiledMethod.getUnsignedNonVolatileOffset() - BYTES_IN_ADDRESS);
}
}
}