Mercurial > hg > truffle
diff agent/src/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCFrame.java @ 0:a61af66fc99e jdk7-b24
Initial load
author | duke |
---|---|
date | Sat, 01 Dec 2007 00:00:00 +0000 |
parents | |
children | a5838065ab24 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCFrame.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,1074 @@ +/* + * Copyright 2000-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package sun.jvm.hotspot.runtime.sparc; + +import java.util.*; + +import sun.jvm.hotspot.asm.sparc.*; +import sun.jvm.hotspot.code.*; +import sun.jvm.hotspot.compiler.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.cdbg.*; +import sun.jvm.hotspot.oops.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.posix.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.utilities.*; + +/** Specialization of and implementation of abstract methods of the + Frame class for the SPARC CPU. (FIXME: this is as quick a port as + possible to get things running; will have to do a better job right + away.) */ + +public class SPARCFrame extends Frame { + // The pc value is the raw return address, plus 8 (pcReturnOffset()). + // the value of sp and youngerSP that is stored in this object + // is always, always, always the value that would be found in the + // register (or window save area) while the target VM was executing. + // The caller of the constructor will alwasy know if has a biased or + // unbiased version of the stack pointer and can convert real (unbiased) + // value via a helper routine we supply. + // Whenever we return sp or youngerSP values we do not return the internal + // value but the real (unbiased) pointers since these are the true, usable + // memory addresses. The outlier case is that of the null pointer. The current + // mechanism makes null pointers always look null whether biased or not. + // This seems to cause no problems. In theory null real pointers could be biased + // just like other values however this has impact on things like addOffsetTo() + // to be able to take an Address that represents null and add an offset to it. + // This doesn't seem worth the bother and the impact on the rest of the code + // when the biasSP and unbiasSP can make this invisible. + // + // The general rule in this code is that when we have a variable like FP, youngerSP, SP + // that these are real (i.e. unbiased) addresses. The instance variables in a Frame are + // always raw values. The other rule is that it except for the frame constructors and + // the unBiasSP helper all methods accept parameters that are real addresses. + // + + /** Optional next-younger SP (used to locate O7, the PC) */ + private Address raw_youngerSP; + + /** Intepreter adjusts the stack pointer to make all locals contiguous */ + private long interpreterSPAdjustmentOffset; + + /** Number of stack entries for longs */ + private static final int WORDS_PER_LONG = 2; + + /** Normal SPARC return is 2 words past PC */ + public static final int PC_RETURN_OFFSET = 8; + + /** Size of each block, in order of increasing address */ + public static final int REGISTER_SAVE_WORDS = 16; + // FIXME: read these from the remote process + //#ifdef _LP64 + // callee_aggregate_return_pointer_words = 0, + //#else + // callee_aggregate_return_pointer_words = 1, + //#endif + public static final int CALLEE_AGGREGATE_RETURN_POINTER_WORDS = 1; + public static final int CALLEE_REGISTER_ARGUMENT_SAVE_AREA_WORDS = 6; + + // offset of each block, in order of increasing address: + public static final int REGISTER_SAVE_WORDS_SP_OFFSET = 0; + public static final int CALLEE_AGGREGATE_RETURN_POINTER_SP_OFFSET = REGISTER_SAVE_WORDS_SP_OFFSET + REGISTER_SAVE_WORDS; + public static final int CALLEE_REGISTER_ARGUMENT_SAVE_AREA_SP_OFFSET = (CALLEE_AGGREGATE_RETURN_POINTER_SP_OFFSET + + CALLEE_AGGREGATE_RETURN_POINTER_WORDS); + public static final int MEMORY_PARAMETER_WORD_SP_OFFSET = (CALLEE_REGISTER_ARGUMENT_SAVE_AREA_SP_OFFSET + + CALLEE_REGISTER_ARGUMENT_SAVE_AREA_WORDS); + public static final int VARARGS_OFFSET = MEMORY_PARAMETER_WORD_SP_OFFSET; + + private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.runtime.sparc.SPARCFrame.DEBUG") != null; + + public static Address unBiasSP(Address raw_sp) { + if (raw_sp != null) { + return raw_sp.addOffsetTo(VM.getVM().getStackBias()); + } else { + return null; + } + } + + public static Address biasSP(Address real_sp) { + if (real_sp != null) { + if (DEBUG) { + System.out.println("biasing realsp: " + real_sp + " biased: " + real_sp.addOffsetTo(-VM.getVM().getStackBias()) ); + } + return real_sp.addOffsetTo(-VM.getVM().getStackBias()); + } else { + if (DEBUG) { + System.out.println("biasing null realsp"); + } + return null; + } + } + // + // This is used to find the younger sp for a thread thatn has stopped but hasn't + // conveniently told us the information where we can find the pc or the frame + // containing the pc that corresponds to last_java_sp. This method will walk + // the frames trying to find the frame which we contains the data we need. + // + public static Address findYoungerSP(Address top, Address find) { + // top and find are unBiased sp values + // we return an unBiased value + Address findRaw = biasSP(find); + if (top == null || find == null || findRaw == null) { + throw new RuntimeException("bad values for findYoungerSP top: " + top + " find: " + find); + } + // It would be unusual to find more than 20 native frames before we find the java frame + // we are looking for. + final int maxFrames = 20; + int count = 0; + Address search = top; + Address next; + Address pc; + if (DEBUG) { + System.out.println("findYoungerSP top: " + top + " find: " + find + " findRaw: " + findRaw); + } + while ( count != maxFrames && search != null) { + next = search.getAddressAt(SPARCRegisters.I6.spOffsetInSavedWindow()); + pc = search.getAddressAt(SPARCRegisters.I7.spOffsetInSavedWindow()); + if (DEBUG) { + System.out.println("findYoungerSP next: " + next + " pc: " + pc); + } + if (next.equals(findRaw)) { + return search; + } + search = unBiasSP(next); + } + if (DEBUG) { + System.out.println("findYoungerSP: never found younger, top: " + top + " find: " + find); + } + return null; + } + + public Address getSP() { + if (DEBUG) { + System.out.println("getSP raw: " + raw_sp + " unbiased: " + unBiasSP(raw_sp)); + } + return unBiasSP(raw_sp); + } + + public Address getID() { + return getSP(); + } + + public Address getYoungerSP() { + if (DEBUG) { + System.out.println("getYoungerSP: " + raw_youngerSP + " unbiased: " + unBiasSP(raw_youngerSP)); + } + return unBiasSP(raw_youngerSP); + } + + /** This constructor relies on the fact that the creator of a frame + has flushed register windows which the frame will refer to, and + that those register windows will not be reloaded until the frame + is done reading and writing the stack. Moreover, if the + "younger_pc" argument points into the register save area of the + next younger frame (though it need not), the register window for + that next younger frame must also stay flushed. (The caller is + responsible for ensuring this.) */ + public SPARCFrame(Address raw_sp, Address raw_youngerSP, boolean youngerFrameIsInterpreted) { + super(); + if (DEBUG) { + System.out.println("Constructing frame(1) raw_sp: " + raw_sp + " raw_youngerSP: " + raw_youngerSP); + } + if (Assert.ASSERTS_ENABLED) { + Assert.that((unBiasSP(raw_sp).andWithMask(VM.getVM().getAddressSize() - 1) == null), + "Expected raw sp likely got real sp, value was " + raw_sp); + if (raw_youngerSP != null) { + Assert.that((unBiasSP(raw_youngerSP).andWithMask(VM.getVM().getAddressSize() - 1) == null), + "Expected raw youngerSP likely got real youngerSP, value was " + raw_youngerSP); + } + } + this.raw_sp = raw_sp; + this.raw_youngerSP = raw_youngerSP; + if (raw_youngerSP == null) { + // make a deficient frame which doesn't know where its PC is + pc = null; + } else { + Address youngerSP = unBiasSP(raw_youngerSP); + pc = youngerSP.getAddressAt(SPARCRegisters.I7.spOffsetInSavedWindow()).addOffsetTo(PC_RETURN_OFFSET); + + if (Assert.ASSERTS_ENABLED) { + Assert.that(youngerSP.getAddressAt(SPARCRegisters.FP.spOffsetInSavedWindow()). + equals(raw_sp), + "youngerSP must be valid"); + } + } + + if (youngerFrameIsInterpreted) { + long IsavedSP = SPARCRegisters.IsavedSP.spOffsetInSavedWindow(); + // compute adjustment to this frame's SP made by its interpreted callee + interpreterSPAdjustmentOffset = 0; + Address savedSP = unBiasSP(getYoungerSP().getAddressAt(IsavedSP)); + if (savedSP == null) { + if ( DEBUG) { + System.out.println("WARNING: IsavedSP was null for frame " + this); + } + } else { + interpreterSPAdjustmentOffset = savedSP.minus(getSP()); + } + } else { + interpreterSPAdjustmentOffset = 0; + } + if ( pc != null) { + // Look for a deopt pc and if it is deopted convert to original pc + CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc); + if (cb != null && cb.isJavaMethod()) { + NMethod nm = (NMethod) cb; + if (pc.equals(nm.deoptBegin())) { + // adjust pc if frame is deoptimized. + pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset()); + deoptimized = true; + } + } + } + } + + /** Make a deficient frame which doesn't know where its PC is (note + no youngerSP argument) */ + public SPARCFrame(Address raw_sp, Address pc) { + super(); + if (DEBUG) { + System.out.println("Constructing frame(2) raw_sp: " + raw_sp ); + } + this.raw_sp = raw_sp; + if (Assert.ASSERTS_ENABLED) { + Assert.that((unBiasSP(raw_sp).andWithMask(VM.getVM().getAddressSize() - 1) == null), + "Expected raw sp likely got real sp, value was " + raw_sp); + } + raw_youngerSP = null; + this.pc = pc; + interpreterSPAdjustmentOffset = 0; + } + + /** Only used internally */ + private SPARCFrame() { + } + + public Object clone() { + SPARCFrame frame = new SPARCFrame(); + frame.raw_sp = raw_sp; + frame.pc = pc; + frame.raw_youngerSP = raw_youngerSP; + frame.interpreterSPAdjustmentOffset = interpreterSPAdjustmentOffset; + frame.deoptimized = deoptimized; + return frame; + } + + public boolean equals(Object arg) { + if (arg == null) { + return false; + } + + if (!(arg instanceof SPARCFrame)) { + return false; + } + + SPARCFrame other = (SPARCFrame) arg; + + return (AddressOps.equal(getSP(), other.getSP()) && + AddressOps.equal(getFP(), other.getFP()) && + AddressOps.equal(getPC(), other.getPC())); + } + + public int hashCode() { + if (raw_sp == null) { + return 0; + } + + return raw_sp.hashCode(); + } + + public String toString() { + Address fp = getFP(); + Address sp = getSP(); + Address youngerSP = getYoungerSP(); + + return "sp: " + (sp == null? "null" : sp.toString()) + + ", younger_sp: " + (youngerSP == null? "null" : youngerSP.toString()) + + ", fp: " + (fp == null? "null" : fp.toString()) + + ", pc: " + (pc == null? "null" : pc.toString()); + } + + /** <P> Identifies a signal handler frame on the stack. </P> + + <P> There are a few different algorithms for doing this, and + they vary from platform to platform. For example, based on a + conversation with Dave Dice, Solaris/x86 will be substantially + simpler to handle than Solaris/SPARC because the signal handler + frame can be identified because of a program counter == -1. </P> + + <P> The dbx group provided code and advice on these topics; the + code below evolved from theirs, but is not correct/robust. + Without going into too many details, it seems that looking for + the incoming argument to the sigacthandler frame (which is what + this code identifies) is not guaranteed to be stable across + versions of Solaris, since that function is supplied by + libthread and is not guaranteed not to clobber I2 before it + calls __sighndlr later. From discussions, it sounds like a + robust algorithm which wouldn't require traversal of the + ucontext chain (used by dbx, but which Dave Dice thinks isn't + robust in the face of libthread -- need to follow up) would be + to be able to properly identify the __sighndlr frame, then get + I2 and treat that as a ucontext. To identify __sighndlr we would + need to look up that symbol in the remote process and look for a + program counter within a certain (small) distance. </P> + + <P> If the underlying Debugger supports CDebugger interface, we + take the approach of __sighnldr symbol. This approach is more robust + compared to the original hueristic approach. Of course, if there + is no CDebugger support, we fallback to the hueristic approach. </P> + + <P> The current implementation seems to work with Solaris 2.8. + A nice property of this system is that if we find a core file + this algorithm doesn't work on, we can change the code and try + again, so I'm putting this in as the current mechanism for + finding signal handler frames on Solaris/SPARC. </P> */ + public boolean isSignalHandlerFrameDbg() { + CDebugger cdbg = VM.getVM().getDebugger().getCDebugger(); + if (cdbg != null) { + LoadObject dso = cdbg.loadObjectContainingPC(getPC()); + if (dso != null) { + ClosestSymbol cs = dso.closestSymbolToPC(getPC()); + if (cs != null && cs.getName().equals("__sighndlr")) { + return true; + } else { + return false; + } + } else { + return false; + } + } else { + if (getYoungerSP() == null) { + // System.err.println(" SPARCFrame.isSignalHandlerFrameDbg: youngerSP = " + getYoungerSP()); + return false; + } + Address i2 = getSP().getAddressAt(SPARCRegisters.I2.spOffsetInSavedWindow()); + if (i2 == null) { + return false; + } + Address fp = getFP(); + // My (mistaken) understanding of the dbx group's code was that + // the signal handler frame could be identified by testing the + // incoming argument to see whether it was a certain distance + // below the frame pointer; in fact, their code did substantially + // more than this (traversal of the ucontext chain, which this + // code can't do because the topmost ucontext is not currently + // available via the proc_service APIs in dbx). The current code + // appears to work, but is probably not robust. + int MAJOR_HACK_OFFSET = 8; // Difference between expected location of the ucontext and reality + // System.err.println(" SPARCFrame.isSignalHandlerFrameDbg: I2 = " + i2 + + // ", fp = " + fp + ", raw_youngerSP = " + getYoungerSP()); + boolean res = i2.equals(fp.addOffsetTo(VM.getVM().getAddressSize() * (REGISTER_SAVE_WORDS + MAJOR_HACK_OFFSET))); + if (res) { + // Qualify this with another test (FIXME: this is a gross heuristic found while testing) + Address sigInfoAddr = getSP().getAddressAt(SPARCRegisters.I5.spOffsetInSavedWindow()); + if (sigInfoAddr == null) { + System.err.println("Frame with fp = " + fp + " looked like a signal handler frame but wasn't"); + res = false; + } + } + return res; + } + } + + public int getSignalNumberDbg() { + // From looking at the stack trace in dbx, it looks like the + // siginfo* comes into sigacthandler in I5. It would be much more + // robust to look at the __sighndlr frame instead, but we can't + // currently identify that frame. + + Address sigInfoAddr = getSP().getAddressAt(SPARCRegisters.I5.spOffsetInSavedWindow()); + // Read si_signo out of siginfo* + return (int) sigInfoAddr.getCIntegerAt(0, 4, false); + } + + public String getSignalNameDbg() { + return POSIXSignals.getSignalName(getSignalNumberDbg()); + } + + public boolean isInterpretedFrameValid() { + if (Assert.ASSERTS_ENABLED) { + Assert.that(isInterpretedFrame(), "Not an interpreted frame"); + } + // These are reasonable sanity checks + if (getFP() == null || (getFP().andWithMask(2 * VM.getVM().getAddressSize() - 1)) != null) { + return false; + } + if (getSP() == null || (getSP().andWithMask(2 * VM.getVM().getAddressSize() - 1)) != null) { + return false; + } + if (getFP().addOffsetTo(INTERPRETER_FRAME_VM_LOCAL_WORDS * VM.getVM().getAddressSize()).lessThan(getSP())) { + return false; + } + // These are hacks to keep us out of trouble. + // The problem with these is that they mask other problems + if (getFP().lessThanOrEqual(getSP())) { // this attempts to deal with unsigned comparison above + return false; + } + if (getFP().minus(getSP()) > 4096 * VM.getVM().getAddressSize()) { // stack frames shouldn't be large. + return false; + } + // FIXME: this is not atomic with respect to GC and is unsuitable + // for use in a non-debugging, or reflective, system. Need to + // figure out how to express this. + if (addressOfInterpreterFrameBCX().getAddressAt(0) == null) { + return false; // BCP not yet set up + } + return true; + } + + //-------------------------------------------------------------------------------- + // Accessors: + // + + /** Accessors */ + + public long frameSize() { + return (getSenderSP().minus(getSP()) / VM.getVM().getAddressSize()); + } + + public Address getLink() { + return unBiasSP(getFP().getAddressAt(SPARCRegisters.FP.spOffsetInSavedWindow())); + } + + // FIXME: not implementable yet + // public void setLink(Address addr) { + // if (Assert.ASSERTS_ENABLED) { + // Assert.that(getLink().equals(addr), "frame nesting is controlled by hardware"); + // } + // } + + public Frame sender(RegisterMap regMap, CodeBlob cb) { + SPARCRegisterMap map = (SPARCRegisterMap) regMap; + + if (Assert.ASSERTS_ENABLED) { + Assert.that(map != null, "map must be set"); + } + + // Default is we don't have to follow them. The sender_for_xxx + // will update it accordingly + map.setIncludeArgumentOops(false); + + if (cb == null && isEntryFrame()) { + return senderForEntryFrame(map); + } + + Address youngerSP = getSP(); + Address sp = getSenderSP(); + boolean isInterpreted = false; + + // FIXME: this is a hack to get stackwalking to work in the face + // of a signal like a SEGV. For debugging purposes it's important + // that (a) we are able to traverse the stack if we take a signal + // and (b) that we get the correct program counter in this + // situation. If we are not using alternate signal stacks then (a) + // seems to work all the time (on SPARC), but (b) is violated for + // the frame just below the signal handler. + + // The mechanism for finding the ucontext is not robust. In + // addition, we may find that we need to be able to fetch more + // registers from the ucontext than just the program counter, + // since the register windows on the stack are "stale". This will + // require substantial restructuring of this frame code, so has + // been avoided for now. + + // It is difficult to find a clean solution for mixing debugging + // situations with VM frame traversal. One could consider + // implementing generic frame traversal in the dbx style and only + // using the VM's stack walking mechanism on a per-frame basis, + // for example to traverse Java-level activations in a compiled + // frame. However, this will probably not interact well with the + // mechanism for finding oops on the stack. + + if (VM.getVM().isDebugging()) { + // If we are a signal handler frame, use a trick: make the + // youngerSP of the caller frame point to the top of the + // ucontext's contained register set. This should allow fetching + // of the registers for the frame just below the signal handler + // frame in the usual fashion. + if (isSignalHandlerFrameDbg()) { + + if (DEBUG) { + System.out.println("SPARCFrame.sender: found signal handler frame"); + } + + // Try to give a valid SP and PC for a "deficient frame" since + // we don't have a real register save area; making this class + // work by reading its information from a ucontext as well as + // a register save area is a major undertaking and has been + // deferred for now. It is very important that the PC is + // correct, which is why we don't just fall through to the + // other code (which would read the PC from the stale register + // window and thereby fail to get the actual location of the + // fault). + + long offset = getMContextAreaOffsetInUContext(); + Address fp = sp; + // System.out.println(" FP: " + fp); + fp = fp.addOffsetTo(getUContextOffset() + getMContextAreaOffsetInUContext()); + // System.out.println(" start of mcontext: " + fp); + // FIXME: put these elsewhere. These are the register numbers + // in /usr/include/sys/regset.h. They might belong in + // SPARCReigsters.java, but we currently don't have that list + // of numbers in the SA code (because all of the registers are + // listed as instances of SPARCRegister) and it appears that + // our numbering of the registers and this one don't match up. + int PC_OFFSET_IN_GREGSET = 1; + int SP_OFFSET_IN_GREGSET = 17; + raw_sp = fp.getAddressAt(VM.getVM().getAddressSize() * SP_OFFSET_IN_GREGSET); + Address pc = fp.getAddressAt(VM.getVM().getAddressSize() * PC_OFFSET_IN_GREGSET); + // System.out.println(" next frame's SP: " + sp + " PC: " + pc); + return new SPARCFrame(raw_sp, pc); + } + } + + if (!VM.getVM().isCore()) { + // Note: The version of this operation on any platform with callee-save + // registers must update the register map (if not null). + // In order to do this correctly, the various subtypes of + // of frame (interpreted, compiled, glue, native), + // must be distinguished. There is no need on SPARC for + // such distinctions, because all callee-save registers are + // preserved for all frames via SPARC-specific mechanisms. + // + // *** HOWEVER, *** if and when we make any floating-point + // registers callee-saved, then we will have to copy over + // the RegisterMap update logic from the Intel code. + + + // The constructor of the sender must know whether this frame is interpreted so it can set the + // sender's _interpreter_sp_adjustment field. + if (VM.getVM().getInterpreter().contains(pc)) { + isInterpreted = true; + if (VM.getVM().isClientCompiler()) { + map.makeIntegerRegsUnsaved(); + map.shiftWindow(sp, youngerSP); + } + } else { + // Find a CodeBlob containing this frame's pc or elide the lookup and use the + // supplied blob which is already known to be associated with this frame. + cb = VM.getVM().getCodeCache().findBlob(pc); + if (cb != null) { + + if (cb.callerMustGCArguments(map.getThread())) { + map.setIncludeArgumentOops(true); + } + + // Update the location of all implicitly saved registers + // as the address of these registers in the register save + // area (for %o registers we use the address of the %i + // register in the next younger frame) + map.shiftWindow(sp, youngerSP); + if (map.getUpdateMap()) { + if (cb.getOopMaps() != null) { + OopMapSet.updateRegisterMap(this, cb, map, VM.getVM().isDebugging()); + } + } + } + } + } // #ifndef CORE + + return new SPARCFrame(biasSP(sp), biasSP(youngerSP), isInterpreted); + } + + protected boolean hasSenderPD() { + try { + // FIXME: should not happen!!! + if (getSP() == null) { + return false; + } + if ( unBiasSP(getSP().getAddressAt(SPARCRegisters.FP.spOffsetInSavedWindow())) == null ) { + return false; + } + return true; + } catch (RuntimeException e) { + if (DEBUG) { + System.out.println("Bad frame " + this); + } + throw e; + } + } + + //-------------------------------------------------------------------------------- + // Return address: + // + + public Address getSenderPC() { + return addressOfI7().getAddressAt(0).addOffsetTo(PC_RETURN_OFFSET); + } + + // FIXME: currently unimplementable + // inline void frame::set_sender_pc(address addr) { *I7_addr() = addr - pc_return_offset; } + + public Address getUnextendedSP() { + return getSP().addOffsetTo(interpreterSPAdjustmentOffset); + } + + public Address getSenderSP() { + return getFP(); + } + + /** Given the next-younger sp for a given frame's sp, compute the + frame. We need the next-younger sp, because its register save + area holds the flushed copy of its I7, which is the PC of the + frame we are interested in. */ + public SPARCFrame afterSave() { + return new SPARCFrame(biasSP(getYoungerSP()), null); + } + + /** Accessors for the instance variables */ + public Address getFP() { + Address sp = getSP(); + if (sp == null) { + System.out.println("SPARCFrame.getFP(): sp == null"); + } + Address fpAddr = sp.addOffsetTo(SPARCRegisters.FP.spOffsetInSavedWindow()); + try { + Address fp = unBiasSP(fpAddr.getAddressAt(0)); + if (fp == null) { + System.out.println("SPARCFrame.getFP(): fp == null (&fp == " + fpAddr + ")"); + } + return fp; + } catch (RuntimeException e) { + System.out.println("SPARCFrame.getFP(): is bad (&fp == " + fpAddr + " sp = " + sp + ")"); + return null; + } + } + + private Address addressOfFPSlot(int index) { + return getFP().addOffsetTo(index * VM.getVM().getAddressSize()); + } + + // FIXME: temporarily elided + // // All frames + // + // intptr_t* fp_addr_at(int index) const { return &fp()[index]; } + // intptr_t* sp_addr_at(int index) const { return &sp()[index]; } + // intptr_t fp_at( int index) const { return *fp_addr_at(index); } + // intptr_t sp_at( int index) const { return *sp_addr_at(index); } + // + // private: + // inline address* I7_addr() const; + // inline address* O7_addr() const; + // + // inline address* I0_addr() const; + // inline address* O0_addr() const; + // + // public: + // // access to SPARC arguments and argument registers + // + // intptr_t* register_addr(Register reg) const { + // return sp_addr_at(reg.sp_offset_in_saved_window()); + // } + // intptr_t* memory_param_addr(int param_ix, bool is_in) const { + // int offset = callee_register_argument_save_area_sp_offset + param_ix; + // if (is_in) + // return fp_addr_at(offset); + // else + // return sp_addr_at(offset); + // } + // intptr_t* param_addr(int param_ix, bool is_in) const { + // if (param_ix >= callee_register_argument_save_area_words) + // return memory_param_addr(param_ix, is_in); + // else if (is_in) + // return register_addr(Argument(param_ix, true).as_register()); + // else { + // // the registers are stored in the next younger frame + // // %%% is this really necessary? + // frame next_younger = after_save(); + // return next_younger.register_addr(Argument(param_ix, true).as_register()); + // } + // } + + //-------------------------------------------------------------------------------- + // Interpreter frames: + // + + /** 2 words, also used to save float regs across calls to C */ + public static final int INTERPRETER_FRAME_D_SCRATCH_FP_OFFSET = -2; + public static final int INTERPRETER_FRAME_L_SCRATCH_FP_OFFSET = -4; + /** For native calls only */ + public static final int INTERPRETER_FRAME_PADDING_OFFSET = -5; + /** For native calls only */ + public static final int INTERPRETER_FRAME_MIRROR_OFFSET = -6; + /** Should be same as above, and should be zero mod 8 */ + public static final int INTERPRETER_FRAME_VM_LOCALS_FP_OFFSET = -6; + public static final int INTERPRETER_FRAME_VM_LOCAL_WORDS = -INTERPRETER_FRAME_VM_LOCALS_FP_OFFSET; + + /** Interpreter frame set-up needs to save 2 extra words in outgoing + param area for class and jnienv arguments for native stubs (see + nativeStubGen_sparc.cpp) */ + public static final int INTERPRETER_FRAME_EXTRA_OUTGOING_ARGUMENT_WORDS = 2; + + // FIXME: elided for now + // + // // the compiler frame has many of the same fields as the interpreter frame + // // %%%%% factor out declarations of the shared fields + // enum compiler_frame_fixed_locals { + // compiler_frame_d_scratch_fp_offset = -2, + // compiler_frame_vm_locals_fp_offset = -2, // should be same as above + // + // compiler_frame_vm_local_words = -compiler_frame_vm_locals_fp_offset + // }; + // + // private: + // + // // where LcpoolCache is saved: + // constantPoolCacheOop* interpreter_frame_cpoolcache_addr() const { + // return (constantPoolCacheOop*)sp_addr_at( LcpoolCache.sp_offset_in_saved_window()); + // } + // + // // where Lmonitors is saved: + // BasicObjectLock** interpreter_frame_monitors_addr() const { + // return (BasicObjectLock**) sp_addr_at( Lmonitors.sp_offset_in_saved_window()); + // } + // intptr_t** interpreter_frame_esp_addr() const { + // return (intptr_t**)sp_addr_at( Lesp.sp_offset_in_saved_window()); + // } + // + // inline void interpreter_frame_set_tos_address(intptr_t* x); + // + // // next two fns read and write Lmonitors value, + // private: + // BasicObjectLock* interpreter_frame_monitors() const { return *interpreter_frame_monitors_addr(); } + // void interpreter_frame_set_monitors(BasicObjectLock* monitors) { *interpreter_frame_monitors_addr() = monitors; } + // + //#ifndef CORE + //inline oop *frame::pd_compiled_argument_to_location(VMReg::Name reg, RegisterMap reg_map, int arg_size) const { + // COMPILER1_ONLY(return (oop *) (arg_size - 1 - reg + sp() + memory_parameter_word_sp_offset); ) + // COMPILER2_ONLY(return oopmapreg_to_location(reg, ®_map); ) + //} + //#endif + + // FIXME: NOT FINISHED + public Address addressOfInterpreterFrameLocals() { + return getSP().addOffsetTo(SPARCRegisters.Llocals.spOffsetInSavedWindow()); + } + + // FIXME: this is not atomic with respect to GC and is unsuitable + // for use in a non-debugging, or reflective, system. + private Address addressOfInterpreterFrameBCX() { + // %%%%% reinterpreting Lbcp as a bcx + return getSP().addOffsetTo(SPARCRegisters.Lbcp.spOffsetInSavedWindow()); + } + + public int getInterpreterFrameBCI() { + // FIXME: this is not atomic with respect to GC and is unsuitable + // for use in a non-debugging, or reflective, system. Need to + // figure out how to express this. + Address bcp = addressOfInterpreterFrameBCX().getAddressAt(0); + OopHandle methodHandle = addressOfInterpreterFrameMethod().getOopHandleAt(0); + Method method = (Method) VM.getVM().getObjectHeap().newOop(methodHandle); + return bcpToBci(bcp, method); + } + + public Address addressOfInterpreterFrameExpressionStack() { + return addressOfInterpreterFrameMonitors().addOffsetTo(-1 * VM.getVM().getAddressSize()); + } + + public int getInterpreterFrameExpressionStackDirection() { + return -1; + } + + /** Top of expression stack */ + public Address addressOfInterpreterFrameTOS() { + return getSP().getAddressAt(SPARCRegisters.Lesp.spOffsetInSavedWindow()).addOffsetTo(VM.getVM().getAddressSize()); + } + + /** Expression stack from top down */ + public Address addressOfInterpreterFrameTOSAt(int slot) { + return addressOfInterpreterFrameTOS().addOffsetTo(slot * VM.getVM().getAddressSize()); + } + + public Address getInterpreterFrameSenderSP() { + if (Assert.ASSERTS_ENABLED) { + Assert.that(isInterpretedFrame(), "interpreted frame expected"); + } + return getFP(); + } + + // FIXME: elided for now + //inline void frame::interpreter_frame_set_tos_address( intptr_t* x ) { + // *interpreter_frame_esp_addr() = x - 1; + //} + + //-------------------------------------------------------------------------------- + // Monitors: + // + + private Address addressOfInterpreterFrameMonitors() { + return getSP().addOffsetTo(SPARCRegisters.Lmonitors.spOffsetInSavedWindow()).getAddressAt(0); + } + + // Monitors + public BasicObjectLock interpreterFrameMonitorBegin() { + int roundedVMLocalWords = Bits.roundTo(INTERPRETER_FRAME_VM_LOCAL_WORDS, WORDS_PER_LONG); + return new BasicObjectLock(addressOfFPSlot(-1 * roundedVMLocalWords)); + } + + public BasicObjectLock interpreterFrameMonitorEnd() { + return new BasicObjectLock(addressOfInterpreterFrameMonitors()); + } + + public int interpreterFrameMonitorSize() { + return Bits.roundTo(BasicObjectLock.size(), WORDS_PER_LONG * (int) VM.getVM().getAddressSize()); + } + + // FIXME: elided for now + // // monitor elements + // + // // in keeping with Intel side: end is lower in memory than begin; + // // and beginning element is oldest element + // // Also begin is one past last monitor. + // + // inline BasicObjectLock* frame::interpreter_frame_monitor_begin() const { + // int rounded_vm_local_words = round_to(frame::interpreter_frame_vm_local_words, WordsPerLong); + // return (BasicObjectLock *)fp_addr_at(-rounded_vm_local_words); + // } + // + // inline BasicObjectLock* frame::interpreter_frame_monitor_end() const { + // return interpreter_frame_monitors(); + // } + // + // + // inline void frame::interpreter_frame_set_monitor_end(BasicObjectLock* value) { + // interpreter_frame_set_monitors(value); + // } + // + // + // inline int frame::interpreter_frame_monitor_size() { + // return round_to(BasicObjectLock::size(), WordsPerLong); + // } + + public Address addressOfInterpreterFrameMethod() { + return getSP().addOffsetTo(SPARCRegisters.Lmethod.spOffsetInSavedWindow()); + } + + public Address addressOfInterpreterFrameCPCache() { + return getSP().addOffsetTo(SPARCRegisters.LcpoolCache.spOffsetInSavedWindow()); + } + + //-------------------------------------------------------------------------------- + // Entry frames: + // + + public JavaCallWrapper getEntryFrameCallWrapper() { + // Note: adjust this code if the link argument in StubGenerator::call_stub() changes! + SPARCArgument link = new SPARCArgument(0, false); + return (JavaCallWrapper) VMObjectFactory.newObject(JavaCallWrapper.class, + getSP().getAddressAt(link.asIn().asRegister().spOffsetInSavedWindow())); + } + + // + // + // inline JavaCallWrapper* frame::entry_frame_call_wrapper() const { + // // note: adjust this code if the link argument in StubGenerator::call_stub() changes! + // const Argument link = Argument(0, false); + // return (JavaCallWrapper*)sp()[link.as_in().as_register().sp_offset_in_saved_window()]; + // } + + //-------------------------------------------------------------------------------- + // Safepoints: + // + + protected Address addressOfSavedOopResult() { + return addressOfO0(); + } + + protected Address addressOfSavedReceiver() { + return addressOfO0(); + } + + + //-------------------------------------------------------------------------------- + // Internals only below this point + // + + private Address addressOfI7() { + return getSP().addOffsetTo(SPARCRegisters.I7.spOffsetInSavedWindow()); + } + + private Address addressOfO7() { + return afterSave().addressOfI7(); + } + + private Address addressOfI0() { + return getSP().addOffsetTo(SPARCRegisters.I0.spOffsetInSavedWindow()); + } + + private Address addressOfO0() { + return afterSave().addressOfI0(); + } + + private static boolean addressesEqual(Address a1, Address a2) { + if ((a1 == null) && (a2 == null)) { + return true; + } + + if ((a1 == null) || (a2 == null)) { + return false; + } + + return (a1.equals(a2)); + } + + + private Frame senderForEntryFrame(RegisterMap regMap) { + SPARCRegisterMap map = (SPARCRegisterMap) regMap; + + if (Assert.ASSERTS_ENABLED) { + Assert.that(map != null, "map must be set"); + } + // Java frame called from C; skip all C frames and return top C + // frame of that chunk as the sender + JavaCallWrapper jcw = getEntryFrameCallWrapper(); + if (Assert.ASSERTS_ENABLED) { + Assert.that(!entryFrameIsFirst(), "next Java fp must be non zero"); + Assert.that(jcw.getLastJavaSP().greaterThan(getSP()), "must be above this frame on stack"); + } + Address lastJavaSP = jcw.getLastJavaSP(); + Address lastJavaPC = jcw.getLastJavaPC(); + map.clear(); + + if (!VM.getVM().isCore()) { + map.makeIntegerRegsUnsaved(); + map.shiftWindow(lastJavaSP, null); + } + + if (Assert.ASSERTS_ENABLED) { + Assert.that(map.getIncludeArgumentOops(), "should be set by clear"); + } + + if (lastJavaPC != null) { + return new SPARCFrame(biasSP(lastJavaSP), lastJavaPC); + } else { + Address youngerSP = getNextYoungerSP(lastJavaSP, getSP()); + return new SPARCFrame(biasSP(lastJavaSP), biasSP(youngerSP), false); + } + } + + private static Address getNextYoungerSP(Address oldSP, Address youngSP) { + Address sp = getNextYoungerSPOrNull(oldSP, youngSP, null); + if (Assert.ASSERTS_ENABLED) { + Assert.that(sp != null, "missed the SP"); + } + return sp; + } + + private static Address getNextYoungerSPOrNull(Address oldSP, Address youngSP, Address sp) { + if (youngSP == null) { + // FIXME + throw new RuntimeException("can not handle null youngSP in debugging system (seems to require register window flush)"); + } + + if (sp == null) { + sp = youngSP; + } + + Address previousSP = null; + + /** Minimum frame size is 16 */ + int maxFrames = (int) (oldSP.minus(sp) / (16 * VM.getVM().getAddressSize())); + + while(!sp.equals(oldSP) && spIsValid(oldSP, youngSP, sp)) { + if (maxFrames-- <= 0) { + // too many frames have gone by; invalid parameters given to this function + break; + } + previousSP = sp; + sp = unBiasSP(sp.getAddressAt(SPARCRegisters.FP.spOffsetInSavedWindow())); + } + + return (sp.equals(oldSP) ? previousSP : null); + } + + private static boolean spIsValid(Address oldSP, Address youngSP, Address sp) { + long mask = VM.getVM().getAddressSize(); + mask = 2 * mask - 1; + return ((sp.andWithMask(mask) == null) && + (sp.lessThanOrEqual(oldSP)) && + (sp.greaterThanOrEqual(youngSP))); + } + + // FIXME: this is a hopefully temporary hack (not sure what is going on) + public long getUContextOffset() { + // FIXME: there is something I clearly don't understand about the + // way the signal handler frame is laid out, because I shouldn't need this extra offset + int MAJOR_HACK_OFFSET = 8; + // System.out.println(" SPARCFrame.isSignalHandlerFrameDbg: I2 = " + i2 + ", fp = " + fp + ", youngerSP = " + youngerSP); + return VM.getVM().getAddressSize() * (REGISTER_SAVE_WORDS + MAJOR_HACK_OFFSET); + } + + public long getMContextAreaOffsetInUContext() { + // From dbx-related sources: + // /* + // * struct sigframe is declaredf in the kernel sources in + // * .../uts/sun4c/os/machdep.c/sendsig() + // * unfortunately we only get a pointer to the 'uc' passed + // * to the sighandler so we need to do this stuff to get + // * to 'rwin'. + // * Have to do it like this to take account of alignment. + // */ + // static struct sigframe { + // struct rwindow rwin; + // ucontext_t uc; + // } sf_help; + + // From /usr/include/sys/ucontext.h: + // #if !defined(_XPG4_2) || defined(__EXTENSIONS__) + // struct ucontext { + // #else + // struct __ucontext { + // #endif + // uint_t uc_flags; + // ucontext_t *uc_link; + // sigset_t uc_sigmask; + // stack_t uc_stack; + // mcontext_t uc_mcontext; + // #ifdef __sparcv9 + // long uc_filler[4]; + // #else /* __sparcv9 */ + // long uc_filler[23]; + // #endif /* __sparcv9 */ + // }; + + // This walks to the start of the gregs in the mcontext_t + // (first entry in that data structure). Really should read + // this from header file. + + // Also not sure exactly how alignment works...maybe should read these offsets from the target VM + // (When you have a hammer, everything looks like a nail) + long offset = VM.getVM().alignUp(4, VM.getVM().getAddressSize()); // uc_flags + offset = VM.getVM().alignUp(offset + VM.getVM().getAddressSize(), 8); // uc_link plus + // doubleword alignment for structs? + offset += 16 + // uc_sigmask + 2 * VM.getVM().getAddressSize() + 4; // uc_stack + offset = VM.getVM().alignUp(offset + VM.getVM().getAddressSize(), 8); // doubleword alignment for structs? + + // System.out.println("SPARCFrame.getMContextAreaOffsetInUContext: offset = " + offset); + + return offset; + } +}