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