1 /* 2 * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2015, 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 this.pc = raw_sp.getAddressAt(-1 * VM.getVM().getAddressSize()); 137 adjustUnextendedSP(); 138 139 // Frame must be fully constructed before this call 140 adjustForDeopt(); 141 142 if (DEBUG) { 143 System.out.println("AARCH64Frame(sp, fp): " + this); 144 dumpStack(); 145 } 146 } 147 148 public AARCH64Frame(Address raw_sp, Address raw_unextendedSp, Address raw_fp, Address pc) { 149 this.raw_sp = raw_sp; 150 this.raw_unextendedSP = raw_unextendedSp; 151 this.raw_fp = raw_fp; 152 this.pc = pc; 153 adjustUnextendedSP(); 154 155 // Frame must be fully constructed before this call 156 adjustForDeopt(); 157 158 if (DEBUG) { 159 System.out.println("AARCH64Frame(sp, unextendedSP, fp, pc): " + this); 160 dumpStack(); 161 } 162 163 } 164 165 public Object clone() { 166 AARCH64Frame frame = new AARCH64Frame(); 167 frame.raw_sp = raw_sp; 168 frame.raw_unextendedSP = raw_unextendedSP; 169 frame.raw_fp = raw_fp; 170 frame.pc = pc; 171 frame.deoptimized = deoptimized; 172 return frame; 173 } 174 175 public boolean equals(Object arg) { 176 if (arg == null) { 177 return false; 178 } 179 180 if (!(arg instanceof AARCH64Frame)) { 181 return false; 182 } 183 184 AARCH64Frame other = (AARCH64Frame) arg; 185 186 return (AddressOps.equal(getSP(), other.getSP()) && 187 AddressOps.equal(getUnextendedSP(), other.getUnextendedSP()) && 188 AddressOps.equal(getFP(), other.getFP()) && 189 AddressOps.equal(getPC(), other.getPC())); 190 } 191 192 public int hashCode() { 193 if (raw_sp == null) { 194 return 0; 195 } 196 197 return raw_sp.hashCode(); 198 } 199 200 public String toString() { 201 return "sp: " + (getSP() == null? "null" : getSP().toString()) + 202 ", unextendedSP: " + (getUnextendedSP() == null? "null" : getUnextendedSP().toString()) + 203 ", fp: " + (getFP() == null? "null" : getFP().toString()) + 204 ", pc: " + (pc == null? "null" : pc.toString()); 205 } 206 207 // accessors for the instance variables 208 public Address getFP() { return raw_fp; } 209 public Address getSP() { return raw_sp; } 210 public Address getID() { return raw_sp; } 211 212 // FIXME: not implemented yet 213 public boolean isSignalHandlerFrameDbg() { return false; } 214 public int getSignalNumberDbg() { return 0; } 215 public String getSignalNameDbg() { return null; } 216 217 public boolean isInterpretedFrameValid() { 218 if (Assert.ASSERTS_ENABLED) { 219 Assert.that(isInterpretedFrame(), "Not an interpreted frame"); 220 } 221 222 // These are reasonable sanity checks 223 if (getFP() == null || getFP().andWithMask(0x3) != null) { 224 return false; 225 } 226 227 if (getSP() == null || getSP().andWithMask(0x3) != null) { 228 return false; 229 } 230 231 if (getFP().addOffsetTo(INTERPRETER_FRAME_INITIAL_SP_OFFSET * VM.getVM().getAddressSize()).lessThan(getSP())) { 232 return false; 233 } 234 235 // These are hacks to keep us out of trouble. 236 // The problem with these is that they mask other problems 237 if (getFP().lessThanOrEqual(getSP())) { 238 // this attempts to deal with unsigned comparison above 239 return false; 240 } 241 242 if (getFP().minus(getSP()) > 4096 * VM.getVM().getAddressSize()) { 243 // stack frames shouldn't be large. 244 return false; 245 } 246 247 return true; 248 } 249 250 // FIXME: not applicable in current system 251 // void patch_pc(Thread* thread, address pc); 252 253 public Frame sender(RegisterMap regMap, CodeBlob cb) { 254 AARCH64RegisterMap map = (AARCH64RegisterMap) regMap; 255 256 if (Assert.ASSERTS_ENABLED) { 257 Assert.that(map != null, "map must be set"); 258 } 259 260 // Default is we done have to follow them. The sender_for_xxx will 261 // update it accordingly 262 map.setIncludeArgumentOops(false); 263 264 if (isEntryFrame()) return senderForEntryFrame(map); 265 if (isInterpretedFrame()) return senderForInterpreterFrame(map); 266 267 if(cb == null) { 268 cb = VM.getVM().getCodeCache().findBlob(getPC()); 269 } else { 270 if (Assert.ASSERTS_ENABLED) { 271 Assert.that(cb.equals(VM.getVM().getCodeCache().findBlob(getPC())), "Must be the same"); 272 } 273 } 274 275 if (cb != null) { 276 return senderForCompiledFrame(map, cb); 277 } 278 279 // Must be native-compiled frame, i.e. the marshaling code for native 280 // methods that exists in the core system. 281 return new AARCH64Frame(getSenderSP(), getLink(), getSenderPC()); 282 } 283 284 private Frame senderForEntryFrame(AARCH64RegisterMap map) { 285 if (DEBUG) { 286 System.out.println("senderForEntryFrame"); 287 } 288 if (Assert.ASSERTS_ENABLED) { 289 Assert.that(map != null, "map must be set"); 290 } 291 // Java frame called from C; skip all C frames and return top C 292 // frame of that chunk as the sender 293 AARCH64JavaCallWrapper jcw = (AARCH64JavaCallWrapper) getEntryFrameCallWrapper(); 294 if (Assert.ASSERTS_ENABLED) { 295 Assert.that(!entryFrameIsFirst(), "next Java fp must be non zero"); 296 Assert.that(jcw.getLastJavaSP().greaterThan(getSP()), "must be above this frame on stack"); 297 } 298 AARCH64Frame fr; 299 if (jcw.getLastJavaPC() != null) { 300 fr = new AARCH64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP(), jcw.getLastJavaPC()); 301 } else { 302 fr = new AARCH64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP()); 303 } 304 map.clear(); 305 if (Assert.ASSERTS_ENABLED) { 306 Assert.that(map.getIncludeArgumentOops(), "should be set by clear"); 307 } 308 return fr; 309 } 310 311 //------------------------------------------------------------------------------ 312 // frame::adjust_unextended_sp 313 private void adjustUnextendedSP() { 314 // If we are returning to a compiled MethodHandle call site, the 315 // saved_fp will in fact be a saved value of the unextended SP. The 316 // simplest way to tell whether we are returning to such a call site 317 // is as follows: 318 319 CodeBlob cb = cb(); 320 NMethod senderNm = (cb == null) ? null : cb.asNMethodOrNull(); 321 if (senderNm != null) { 322 // If the sender PC is a deoptimization point, get the original 323 // PC. For MethodHandle call site the unextended_sp is stored in 324 // saved_fp. 325 if (senderNm.isDeoptMhEntry(getPC())) { 326 // DEBUG_ONLY(verifyDeoptMhOriginalPc(senderNm, getFP())); 327 raw_unextendedSP = getFP(); 328 } 329 else if (senderNm.isDeoptEntry(getPC())) { 330 // DEBUG_ONLY(verifyDeoptOriginalPc(senderNm, raw_unextendedSp)); 331 } 332 else if (senderNm.isMethodHandleReturn(getPC())) { 333 raw_unextendedSP = getFP(); 334 } 335 } 336 } 337 338 private Frame senderForInterpreterFrame(AARCH64RegisterMap map) { 339 if (DEBUG) { 340 System.out.println("senderForInterpreterFrame"); 341 } 342 Address unextendedSP = addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0); 343 Address sp = addressOfStackSlot(SENDER_SP_OFFSET); 344 // We do not need to update the callee-save register mapping because above 345 // us is either another interpreter frame or a converter-frame, but never 346 // directly a compiled frame. 347 // 11/24/04 SFG. With the removal of adapter frames this is no longer true. 348 // However c2 no longer uses callee save register for java calls so there 349 // are no callee register to find. 350 351 if (map.getUpdateMap()) 352 updateMapWithSavedLink(map, addressOfStackSlot(LINK_OFFSET)); 353 354 return new AARCH64Frame(sp, unextendedSP, getLink(), getSenderPC()); 355 } 356 357 private void updateMapWithSavedLink(RegisterMap map, Address savedFPAddr) { 358 map.setLocation(fp, savedFPAddr); 359 } 360 361 private Frame senderForCompiledFrame(AARCH64RegisterMap map, CodeBlob cb) { 362 if (DEBUG) { 363 System.out.println("senderForCompiledFrame"); 364 } 365 366 // 367 // NOTE: some of this code is (unfortunately) duplicated AARCH64CurrentFrameGuess 368 // 369 370 if (Assert.ASSERTS_ENABLED) { 371 Assert.that(map != null, "map must be set"); 372 } 373 374 // frame owned by optimizing compiler 375 if (Assert.ASSERTS_ENABLED) { 376 Assert.that(cb.getFrameSize() >= 0, "must have non-zero frame size"); 377 } 378 Address senderSP = getUnextendedSP().addOffsetTo(cb.getFrameSize()); 379 380 // The return_address is always the word on the stack 381 Address senderPC = senderSP.getAddressAt(-1 * VM.getVM().getAddressSize()); 382 383 // This is the saved value of FP which may or may not really be an FP. 384 // It is only an FP if the sender is an interpreter frame. 385 Address savedFPAddr = senderSP.addOffsetTo(- SENDER_SP_OFFSET * VM.getVM().getAddressSize()); 386 387 if (map.getUpdateMap()) { 388 // Tell GC to use argument oopmaps for some runtime stubs that need it. 389 // For C1, the runtime stub might not have oop maps, so set this flag 390 // outside of update_register_map. 391 map.setIncludeArgumentOops(cb.callerMustGCArguments()); 392 393 if (cb.getOopMaps() != null) { 394 OopMapSet.updateRegisterMap(this, cb, map, true); 395 } 396 397 // Since the prolog does the save and restore of FP there is no oopmap 398 // for it so we must fill in its location as if there was an oopmap entry 399 // since if our caller was compiled code there could be live jvm state in it. 400 updateMapWithSavedLink(map, savedFPAddr); 401 } 402 403 return new AARCH64Frame(senderSP, savedFPAddr.getAddressAt(0), senderPC); 404 } 405 406 protected boolean hasSenderPD() { 407 return true; 408 } 409 410 public long frameSize() { 411 return (getSenderSP().minus(getSP()) / VM.getVM().getAddressSize()); 412 } 413 414 public Address getLink() { 415 try { 416 if (DEBUG) { 417 System.out.println("Reading link at " + addressOfStackSlot(LINK_OFFSET) 418 + " = " + addressOfStackSlot(LINK_OFFSET).getAddressAt(0)); 419 } 420 return addressOfStackSlot(LINK_OFFSET).getAddressAt(0); 421 } catch (Exception e) { 422 if (DEBUG) 423 System.out.println("Returning null"); 424 return null; 425 } 426 } 427 428 // FIXME: not implementable yet 429 //inline void frame::set_link(intptr_t* addr) { *(intptr_t **)addr_at(link_offset) = addr; } 430 431 public Address getUnextendedSP() { return raw_unextendedSP; } 432 433 // Return address: 434 public Address getSenderPCAddr() { return addressOfStackSlot(RETURN_ADDR_OFFSET); } 435 public Address getSenderPC() { return getSenderPCAddr().getAddressAt(0); } 436 437 // return address of param, zero origin index. 438 public Address getNativeParamAddr(int idx) { 439 return addressOfStackSlot(NATIVE_FRAME_INITIAL_PARAM_OFFSET + idx); 440 } 441 442 public Address getSenderSP() { return addressOfStackSlot(SENDER_SP_OFFSET); } 443 444 public Address addressOfInterpreterFrameLocals() { 445 return addressOfStackSlot(INTERPRETER_FRAME_LOCALS_OFFSET); 446 } 447 448 private Address addressOfInterpreterFrameBCX() { 449 return addressOfStackSlot(INTERPRETER_FRAME_BCX_OFFSET); 450 } 451 452 public int getInterpreterFrameBCI() { 453 // FIXME: this is not atomic with respect to GC and is unsuitable 454 // for use in a non-debugging, or reflective, system. Need to 455 // figure out how to express this. 456 Address bcp = addressOfInterpreterFrameBCX().getAddressAt(0); 457 Address methodHandle = addressOfInterpreterFrameMethod().getAddressAt(0); 458 Method method = (Method)Metadata.instantiateWrapperFor(methodHandle); 459 return bcpToBci(bcp, method); 460 } 461 462 public Address addressOfInterpreterFrameMDX() { 463 return addressOfStackSlot(INTERPRETER_FRAME_MDX_OFFSET); 464 } 465 466 // FIXME 467 //inline int frame::interpreter_frame_monitor_size() { 468 // return BasicObjectLock::size(); 469 //} 470 471 // expression stack 472 // (the max_stack arguments are used by the GC; see class FrameClosure) 473 474 public Address addressOfInterpreterFrameExpressionStack() { 475 Address monitorEnd = interpreterFrameMonitorEnd().address(); 476 return monitorEnd.addOffsetTo(-1 * VM.getVM().getAddressSize()); 477 } 478 479 public int getInterpreterFrameExpressionStackDirection() { return -1; } 480 481 // top of expression stack 482 public Address addressOfInterpreterFrameTOS() { 483 return getSP(); 484 } 485 486 /** Expression stack from top down */ 487 public Address addressOfInterpreterFrameTOSAt(int slot) { 488 return addressOfInterpreterFrameTOS().addOffsetTo(slot * VM.getVM().getAddressSize()); 489 } 490 491 public Address getInterpreterFrameSenderSP() { 492 if (Assert.ASSERTS_ENABLED) { 493 Assert.that(isInterpretedFrame(), "interpreted frame expected"); 494 } 495 return addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0); 496 } 497 498 // Monitors 499 public BasicObjectLock interpreterFrameMonitorBegin() { 500 return new BasicObjectLock(addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET)); 501 } 502 503 public BasicObjectLock interpreterFrameMonitorEnd() { 504 Address result = addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET).getAddressAt(0); 505 if (Assert.ASSERTS_ENABLED) { 506 // make sure the pointer points inside the frame 507 Assert.that(AddressOps.gt(getFP(), result), "result must < than frame pointer"); 508 Assert.that(AddressOps.lte(getSP(), result), "result must >= than stack pointer"); 509 } 510 return new BasicObjectLock(result); 511 } 512 513 public int interpreterFrameMonitorSize() { 514 return BasicObjectLock.size(); 515 } 516 517 // Method 518 public Address addressOfInterpreterFrameMethod() { 519 return addressOfStackSlot(INTERPRETER_FRAME_METHOD_OFFSET); 520 } 521 522 // Constant pool cache 523 public Address addressOfInterpreterFrameCPCache() { 524 return addressOfStackSlot(INTERPRETER_FRAME_CACHE_OFFSET); 525 } 526 527 // Entry frames 528 public JavaCallWrapper getEntryFrameCallWrapper() { 529 return new AARCH64JavaCallWrapper(addressOfStackSlot(ENTRY_FRAME_CALL_WRAPPER_OFFSET).getAddressAt(0)); 530 } 531 532 protected Address addressOfSavedOopResult() { 533 // offset is 2 for compiler2 and 3 for compiler1 534 return getSP().addOffsetTo((VM.getVM().isClientCompiler() ? 2 : 3) * 535 VM.getVM().getAddressSize()); 536 } 537 538 protected Address addressOfSavedReceiver() { 539 return getSP().addOffsetTo(-4 * VM.getVM().getAddressSize()); 540 } 541 542 private void dumpStack() { 543 for (Address addr = getSP().addOffsetTo(-4 * VM.getVM().getAddressSize()); 544 AddressOps.lt(addr, getSP()); 545 addr = addr.addOffsetTo(VM.getVM().getAddressSize())) { 546 System.out.println(addr + ": " + addr.getAddressAt(0)); 547 } 548 System.out.println("-----------------------"); 549 for (Address addr = getSP(); 550 AddressOps.lte(addr, getSP().addOffsetTo(20 * VM.getVM().getAddressSize())); 551 addr = addr.addOffsetTo(VM.getVM().getAddressSize())) { 552 System.out.println(addr + ": " + addr.getAddressAt(0)); 553 } 554 } 555 }