--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCFrame.java Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,1073 @@
+/*
+ * 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 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.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) {
+ ImmutableOopMapSet.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;
+ public static final int INTERPRETER_FRAME_MIRROR_OFFSET = -5;
+ 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 = align_up(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 align_up(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;
+ }
+}