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