| /* |
| * Copyright (c) 2000, 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 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.deoptHandlerBegin())) { |
| // 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; |
| } |
| |
| Address methodHandle = addressOfInterpreterFrameMethod().getAddressAt(0); |
| |
| if (VM.getVM().getObjectHeap().isValidMethod(methodHandle) == false) { |
| 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. |
| Address bcx = addressOfInterpreterFrameBCX().getAddressAt(0); |
| |
| Method method; |
| try { |
| method = (Method)Metadata.instantiateWrapperFor(methodHandle); |
| } catch (UnknownOopException ex) { |
| return false; |
| } |
| int bci = bcpToBci(bcx, method); |
| //validate bci |
| if (bci < 0) return false; |
| |
| 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 (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); |
| return new SPARCFrame(raw_sp, pc); |
| } |
| } |
| |
| // 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; |
| 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) { |
| // 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.callerMustGCArguments()) { |
| map.setIncludeArgumentOops(true); |
| } |
| if (cb.getOopMaps() != null) { |
| OopMapSet.updateRegisterMap(this, cb, map, VM.getVM().isDebugging()); |
| } |
| } |
| } |
| } |
| |
| 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: |
| // ConstantPoolCache** interpreter_frame_cpoolcache_addr() const { |
| // return (ConstantPoolCache**)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); |
| Address methodHandle = addressOfInterpreterFrameMethod().getAddressAt(0); |
| Method method = (Method)Metadata.instantiateWrapperFor(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(); |
| |
| 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; |
| } |
| } |