1 /*
   2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 package sun.jvm.hotspot.runtime.ppc64;
  26 
  27 import java.util.*;
  28 import sun.jvm.hotspot.code.*;
  29 import sun.jvm.hotspot.compiler.*;
  30 import sun.jvm.hotspot.debugger.*;
  31 import sun.jvm.hotspot.oops.*;
  32 import sun.jvm.hotspot.runtime.*;
  33 import sun.jvm.hotspot.types.*;
  34 import sun.jvm.hotspot.utilities.*;
  35 
  36 /** Specialization of and implementation of abstract methods of the
  37     Frame class for the ppc64 family of CPUs. */
  38 
  39 public class PPC64Frame extends Frame {
  40   private static final boolean DEBUG;
  41   static {
  42     DEBUG = System.getProperty("sun.jvm.hotspot.runtime.ppc64.PPC64Frame.DEBUG") != null;
  43   }
  44 
  45   // All frames
  46   private static final int SENDER_SP_OFFSET           =  0;
  47 
  48   // Interpreter frames
  49   private static final int INTERPRETER_FRAME_MIRROR_OFFSET = -3; // for native calls only
  50   private static final int INTERPRETER_FRAME_SENDER_SP_OFFSET = -4;
  51   private static final int INTERPRETER_FRAME_LAST_SP_OFFSET = INTERPRETER_FRAME_SENDER_SP_OFFSET - 1;
  52   private static final int INTERPRETER_FRAME_MDX_OFFSET = INTERPRETER_FRAME_LAST_SP_OFFSET -1;
  53   private static final int INTERPRETER_FRAME_ESP_OFFSET = INTERPRETER_FRAME_MDX_OFFSET - 1;
  54   private static final int INTERPRETER_FRAME_BCX_OFFSET = INTERPRETER_FRAME_ESP_OFFSET - 1;
  55   private static final int INTERPRETER_FRAME_CACHE_OFFSET =INTERPRETER_FRAME_BCX_OFFSET - 1;
  56   private static final int INTERPRETER_FRAME_MONITORS_OFFSET = INTERPRETER_FRAME_CACHE_OFFSET - 1;
  57   private static final int INTERPRETER_FRAME_LOCALS_OFFSET = INTERPRETER_FRAME_MONITORS_OFFSET - 1;
  58   private static final int INTERPRETER_FRAME_METHOD_OFFSET = INTERPRETER_FRAME_LOCALS_OFFSET - 1;
  59   private static final int INTERPRETER_FRAME_INITIAL_SP_OFFSET = INTERPRETER_FRAME_BCX_OFFSET - 1; // FIXME: probably wrong, but unused anyway
  60   private static final int INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET;
  61   private static final int INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET;
  62 
  63   // Entry frames
  64   private static int ENTRY_FRAME_CALL_WRAPPER_OFFSET;
  65 
  66   // Native frames
  67   private static int NATIVE_FRAME_INITIAL_PARAM_OFFSET;
  68 
  69 
  70   static {
  71     VM.registerVMInitializedObserver(new Observer() {
  72       public void update(Observable o, Object data) {
  73         initialize(VM.getVM().getTypeDataBase());
  74       }
  75     });
  76   }
  77 
  78   private static synchronized void initialize(TypeDataBase db) {
  79     int abi_minframe_size = db.lookupIntConstant("frame::abi_minframe_size").intValue();
  80     int entry_frame_locals_size = db.lookupIntConstant("frame::entry_frame_locals_size").intValue();
  81     int wordLength = (int) VM.getVM().getAddressSize();
  82     NATIVE_FRAME_INITIAL_PARAM_OFFSET = -abi_minframe_size/wordLength;
  83     ENTRY_FRAME_CALL_WRAPPER_OFFSET = -entry_frame_locals_size/wordLength;
  84   }
  85 
  86 
  87   // an additional field beyond sp and pc:
  88   Address raw_fp; // frame pointer
  89   private Address raw_unextendedSP;
  90 
  91   private PPC64Frame() {
  92   }
  93 
  94   private void adjustForDeopt() {
  95     if ( pc != null) {
  96       // Look for a deopt pc and if it is deopted convert to original pc
  97       CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc);
  98       if (cb != null && cb.isJavaMethod()) {
  99         NMethod nm = (NMethod) cb;
 100         if (pc.equals(nm.deoptHandlerBegin())) {
 101           if (Assert.ASSERTS_ENABLED) {
 102             Assert.that(this.getUnextendedSP() != null, "null SP in Java frame");
 103           }
 104           // adjust pc if frame is deoptimized.
 105           pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset());
 106           deoptimized = true;
 107         }
 108       }
 109     }
 110   }
 111 
 112   public PPC64Frame(Address raw_sp, Address raw_fp, Address pc) {
 113     this.raw_sp = raw_sp;
 114     this.raw_unextendedSP = raw_sp;
 115     if (raw_fp == null) {
 116       this.raw_fp = raw_sp.getAddressAt(0);
 117     } else {
 118       this.raw_fp = raw_fp;
 119     }
 120     if (pc == null) {
 121       this.pc = raw_sp.getAddressAt(2 * VM.getVM().getAddressSize());
 122     } else {
 123       this.pc = pc;
 124     }
 125     adjustUnextendedSP();
 126 
 127     // Frame must be fully constructed before this call
 128     adjustForDeopt();
 129 
 130     if (DEBUG) {
 131       System.out.println("PPC64Frame(sp, fp, pc): " + this);
 132       dumpStack();
 133     }
 134   }
 135 
 136   public PPC64Frame(Address raw_sp, Address raw_fp) {
 137     this.raw_sp = raw_sp;
 138     this.raw_unextendedSP = raw_sp;
 139     if (raw_fp == null) {
 140       this.raw_fp = raw_sp.getAddressAt(0);
 141     } else {
 142       this.raw_fp = raw_fp;
 143     }
 144     this.pc = raw_sp.getAddressAt(2 * VM.getVM().getAddressSize());
 145     adjustUnextendedSP();
 146 
 147     // Frame must be fully constructed before this call
 148     adjustForDeopt();
 149 
 150     if (DEBUG) {
 151       System.out.println("PPC64Frame(sp, fp): " + this);
 152       dumpStack();
 153     }
 154   }
 155 
 156   public PPC64Frame(Address raw_sp, Address raw_unextendedSp, Address raw_fp, Address pc) {
 157     this.raw_sp = raw_sp;
 158     this.raw_unextendedSP = raw_unextendedSp;
 159     if (raw_fp == null) {
 160       this.raw_fp = raw_sp.getAddressAt(0);
 161     } else {
 162       this.raw_fp = raw_fp;
 163     }
 164     if (pc == null) {
 165       this.pc = raw_sp.getAddressAt(2 * VM.getVM().getAddressSize());
 166     } else {
 167       this.pc = pc;
 168     }
 169     adjustUnextendedSP();
 170 
 171     // Frame must be fully constructed before this call
 172     adjustForDeopt();
 173 
 174     if (DEBUG) {
 175       System.out.println("PPC64Frame(sp, unextendedSP, fp, pc): " + this);
 176       dumpStack();
 177     }
 178 
 179   }
 180 
 181   public Object clone() {
 182     PPC64Frame frame = new PPC64Frame();
 183     frame.raw_sp = raw_sp;
 184     frame.raw_unextendedSP = raw_unextendedSP;
 185     frame.raw_fp = raw_fp;
 186     frame.pc = pc;
 187     frame.deoptimized = deoptimized;
 188     return frame;
 189   }
 190 
 191   public boolean equals(Object arg) {
 192     if (arg == null) {
 193       return false;
 194     }
 195 
 196     if (!(arg instanceof PPC64Frame)) {
 197       return false;
 198     }
 199 
 200     PPC64Frame other = (PPC64Frame) arg;
 201 
 202     return (AddressOps.equal(getSP(), other.getSP()) &&
 203         AddressOps.equal(getUnextendedSP(), other.getUnextendedSP()) &&
 204         AddressOps.equal(getFP(), other.getFP()) &&
 205         AddressOps.equal(getPC(), other.getPC()));
 206   }
 207 
 208   public int hashCode() {
 209     if (raw_sp == null) {
 210       return 0;
 211     }
 212 
 213     return raw_sp.hashCode();
 214   }
 215 
 216   public String toString() {
 217     return "sp: " + (getSP() == null ? "null" : getSP().toString()) +
 218         ", unextendedSP: " + (getUnextendedSP() == null ? "null" : getUnextendedSP().toString()) +
 219         ", fp: " + (getFP() == null ? "null" : getFP().toString()) +
 220         ", pc: " + (pc == null ? "null" : pc.toString());
 221   }
 222 
 223   // accessors for the instance variables
 224   public Address getFP() { return raw_fp; }
 225   public Address getSP() { return raw_sp; }
 226   public Address getID() { return raw_sp; }
 227 
 228   // FIXME: not implemented yet (should be done for Solaris/PPC64)
 229   public boolean isSignalHandlerFrameDbg() { return false; }
 230   public int     getSignalNumberDbg()      { return 0;     }
 231   public String  getSignalNameDbg()        { return null;  }
 232 
 233   public boolean isInterpretedFrameValid() {
 234     if (Assert.ASSERTS_ENABLED) {
 235       Assert.that(isInterpretedFrame(), "Not an interpreted frame");
 236     }
 237 
 238     // These are reasonable sanity checks
 239     if (getFP() == null || getFP().andWithMask(0x3) != null) {
 240       return false;
 241     }
 242 
 243     if (getSP() == null || getSP().andWithMask(0x3) != null) {
 244       return false;
 245     }
 246 
 247     // These are hacks to keep us out of trouble.
 248     // The problem with these is that they mask other problems
 249     if (getFP().lessThanOrEqual(getSP())) {
 250       // this attempts to deal with unsigned comparison above
 251       return false;
 252     }
 253 
 254     if (getFP().minus(getSP()) > 4096 * VM.getVM().getAddressSize()) {
 255       // stack frames shouldn't be large.
 256       return false;
 257     }
 258 
 259     return true;
 260   }
 261 
 262   // FIXME: not applicable in current system
 263   //  void    patch_pc(Thread* thread, address pc);
 264 
 265   public Frame sender(RegisterMap regMap, CodeBlob cb) {
 266     PPC64RegisterMap map = (PPC64RegisterMap) regMap;
 267 
 268     if (Assert.ASSERTS_ENABLED) {
 269       Assert.that(map != null, "map must be set");
 270     }
 271 
 272     // Default is we done have to follow them. The sender_for_xxx will
 273     // update it accordingly
 274     map.setIncludeArgumentOops(false);
 275 
 276     if (isEntryFrame()) return senderForEntryFrame(map);
 277     if (isInterpretedFrame()) return senderForInterpreterFrame(map);
 278 
 279     if(cb == null) {
 280       cb = VM.getVM().getCodeCache().findBlob(getPC());
 281     } else {
 282       if (Assert.ASSERTS_ENABLED) {
 283         Assert.that(cb.equals(VM.getVM().getCodeCache().findBlob(getPC())), "Must be the same");
 284       }
 285     }
 286 
 287     if (cb != null) {
 288       return senderForCompiledFrame(map, cb);
 289     }
 290 
 291     // Must be native-compiled frame, i.e. the marshaling code for native
 292     // methods that exists in the core system.
 293     return new PPC64Frame(getSenderSP(), getLink(), getSenderPC());
 294   }
 295 
 296   private Frame senderForEntryFrame(PPC64RegisterMap map) {
 297     if (DEBUG) {
 298       System.out.println("senderForEntryFrame");
 299     }
 300     if (Assert.ASSERTS_ENABLED) {
 301       Assert.that(map != null, "map must be set");
 302     }
 303     // Java frame called from C; skip all C frames and return top C
 304     // frame of that chunk as the sender
 305     PPC64JavaCallWrapper jcw = (PPC64JavaCallWrapper) getEntryFrameCallWrapper();
 306     if (Assert.ASSERTS_ENABLED) {
 307       Assert.that(!entryFrameIsFirst(), "next Java fp must be non zero");
 308       Assert.that(jcw.getLastJavaSP().greaterThan(getSP()), "must be above this frame on stack");
 309     }
 310     PPC64Frame fr;
 311     if (jcw.getLastJavaPC() != null) {
 312       fr = new PPC64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP(), jcw.getLastJavaPC());
 313     } else {
 314       fr = new PPC64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP());
 315     }
 316     map.clear();
 317     if (Assert.ASSERTS_ENABLED) {
 318       Assert.that(map.getIncludeArgumentOops(), "should be set by clear");
 319     }
 320     return fr;
 321   }
 322 
 323   //------------------------------------------------------------------------------
 324   // frame::adjust_unextended_sp
 325   private void adjustUnextendedSP() {
 326     raw_unextendedSP = getFP();
 327   }
 328   private Frame senderForInterpreterFrame(PPC64RegisterMap map) {
 329     if (DEBUG) {
 330       System.out.println("senderForInterpreterFrame");
 331     }
 332     Address unextendedSP = addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0);
 333     Address sp = getSenderSP();
 334 
 335     return new PPC64Frame(sp, unextendedSP, getLink(), getSenderPC());
 336   }
 337 
 338 
 339   private Frame senderForCompiledFrame(PPC64RegisterMap map, CodeBlob cb) {
 340     if (DEBUG) {
 341       System.out.println("senderForCompiledFrame");
 342     }
 343 
 344     //
 345     // NOTE: some of this code is (unfortunately) duplicated in PPC64CurrentFrameGuess
 346     //
 347 
 348     if (Assert.ASSERTS_ENABLED) {
 349       Assert.that(map != null, "map must be set");
 350     }
 351 
 352     // frame owned by optimizing compiler
 353     if (Assert.ASSERTS_ENABLED) {
 354       Assert.that(cb.getFrameSize() >= 0, "must have non-zero frame size");
 355     }
 356     Address senderSP = getSenderSP();
 357 
 358     Address senderPC = getSenderPC();
 359 
 360     if (map.getUpdateMap()) {
 361       // Tell GC to use argument oopmaps for some runtime stubs that need it.
 362       // For C1, the runtime stub might not have oop maps, so set this flag
 363       // outside of update_register_map.
 364       map.setIncludeArgumentOops(cb.callerMustGCArguments());
 365 
 366       if (cb.getOopMaps() != null) {
 367         OopMapSet.updateRegisterMap(this, cb, map, true);
 368       }
 369     }
 370 
 371     return new PPC64Frame(senderSP, getLink(), senderPC);
 372   }
 373 
 374   protected boolean hasSenderPD() {
 375     // FIXME
 376     return true;
 377   }
 378 
 379   public long frameSize() {
 380     return (getSenderSP().minus(getSP()) / VM.getVM().getAddressSize());
 381   }
 382 
 383   public Address getLink() {
 384     return getSenderSP().getAddressAt(0);
 385   }
 386 
 387   public Address getUnextendedSP() { return raw_unextendedSP; }
 388 
 389   // Return address:
 390   public Address getSenderPC()     { return getSenderSP().getAddressAt(2 * VM.getVM().getAddressSize()); }
 391 
 392   // return address of param, zero origin index.
 393   // MPJ note:   Appears to be unused.
 394   public Address getNativeParamAddr(int idx) {
 395     return null;
 396     // return addressOfStackSlot(NATIVE_FRAME_INITIAL_PARAM_OFFSET + idx);
 397   }
 398 
 399   public Address getSenderSP()     { return getFP(); }
 400   public Address addressOfInterpreterFrameLocals() {
 401     return addressOfStackSlot(INTERPRETER_FRAME_LOCALS_OFFSET);
 402   }
 403 
 404   private Address addressOfInterpreterFrameBCX() {
 405     return addressOfStackSlot(INTERPRETER_FRAME_BCX_OFFSET);
 406   }
 407 
 408   public int getInterpreterFrameBCI() {
 409     // FIXME: this is not atomic with respect to GC and is unsuitable
 410     // for use in a non-debugging, or reflective, system. Need to
 411     // figure out how to express this.
 412     Address bcp = addressOfInterpreterFrameBCX().getAddressAt(0);
 413     Address methodHandle = addressOfInterpreterFrameMethod().getAddressAt(0);
 414     Method method = (Method)Metadata.instantiateWrapperFor(methodHandle);
 415     return bcpToBci(bcp, method);
 416   }
 417 
 418   public Address addressOfInterpreterFrameMDX() {
 419     return addressOfStackSlot(INTERPRETER_FRAME_MDX_OFFSET);
 420   }
 421 
 422   // FIXME
 423   //inline int frame::interpreter_frame_monitor_size() {
 424   //  return BasicObjectLock::size();
 425   //}
 426 
 427   // expression stack
 428   // (the max_stack arguments are used by the GC; see class FrameClosure)
 429 
 430   public Address addressOfInterpreterFrameExpressionStack() {
 431     Address monitorEnd = interpreterFrameMonitorEnd().address();
 432     return monitorEnd.addOffsetTo(-1 * VM.getVM().getAddressSize());
 433   }
 434 
 435   public int getInterpreterFrameExpressionStackDirection() { return -1; }
 436 
 437   // top of expression stack
 438   public Address addressOfInterpreterFrameTOS() {
 439     return getSP();
 440   }
 441 
 442   /** Expression stack from top down */
 443   public Address addressOfInterpreterFrameTOSAt(int slot) {
 444     return addressOfInterpreterFrameTOS().addOffsetTo(slot * VM.getVM().getAddressSize());
 445   }
 446 
 447   public Address getInterpreterFrameSenderSP() {
 448     if (Assert.ASSERTS_ENABLED) {
 449       Assert.that(isInterpretedFrame(), "interpreted frame expected");
 450     }
 451     return addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0);
 452   }
 453 
 454   // Monitors
 455   public BasicObjectLock interpreterFrameMonitorBegin() {
 456     return new BasicObjectLock(addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET));
 457   }
 458 
 459   public BasicObjectLock interpreterFrameMonitorEnd() {
 460     Address result = addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET).getAddressAt(0);
 461     if (Assert.ASSERTS_ENABLED) {
 462       // make sure the pointer points inside the frame
 463       Assert.that(AddressOps.gt(getFP(), result), "result must <  than frame pointer");
 464       Assert.that(AddressOps.lte(getSP(), result), "result must >= than stack pointer");
 465     }
 466     return new BasicObjectLock(result);
 467   }
 468 
 469   public int interpreterFrameMonitorSize() {
 470     return BasicObjectLock.size();
 471   }
 472 
 473   // Method
 474   public Address addressOfInterpreterFrameMethod() {
 475     return addressOfStackSlot(INTERPRETER_FRAME_METHOD_OFFSET);
 476   }
 477 
 478   // Constant pool cache
 479   public Address addressOfInterpreterFrameCPCache() {
 480     return addressOfStackSlot(INTERPRETER_FRAME_CACHE_OFFSET);
 481   }
 482 
 483   // Entry frames
 484   public JavaCallWrapper getEntryFrameCallWrapper() {
 485     return new PPC64JavaCallWrapper(addressOfStackSlot(ENTRY_FRAME_CALL_WRAPPER_OFFSET).getAddressAt(0));
 486   }
 487 
 488   protected Address addressOfSavedOopResult() {
 489     // offset is 2 for compiler2 and 3 for compiler1
 490     return getSP().addOffsetTo((VM.getVM().isClientCompiler() ? 2 : 3) *
 491         VM.getVM().getAddressSize());
 492   }
 493 
 494   protected Address addressOfSavedReceiver() {
 495     return getSP().addOffsetTo(-4 * VM.getVM().getAddressSize());
 496   }
 497 
 498   private void dumpStack() {
 499     if (getFP() != null) {
 500       for (Address addr = getSP().addOffsetTo(-5 * VM.getVM().getAddressSize());
 501           AddressOps.lte(addr, getFP().addOffsetTo(5 * VM.getVM().getAddressSize()));
 502           addr = addr.addOffsetTo(VM.getVM().getAddressSize())) {
 503         System.out.println(addr + ": " + addr.getAddressAt(0));
 504       }
 505     } else {
 506       for (Address addr = getSP().addOffsetTo(-5 * VM.getVM().getAddressSize());
 507           AddressOps.lte(addr, getSP().addOffsetTo(20 * VM.getVM().getAddressSize()));
 508           addr = addr.addOffsetTo(VM.getVM().getAddressSize())) {
 509         System.out.println(addr + ": " + addr.getAddressAt(0));
 510       }
 511     }
 512   }
 513 }