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 }