001 /* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013 package org.jikesrvm.runtime; 014 015 import org.jikesrvm.ArchitectureSpecific; 016 import org.jikesrvm.ArchitectureSpecific.Registers; 017 import org.jikesrvm.VM; 018 import org.jikesrvm.Constants; 019 import org.jikesrvm.Services; 020 import org.jikesrvm.classloader.RVMArray; 021 import org.jikesrvm.classloader.RVMClass; 022 import org.jikesrvm.classloader.DynamicTypeCheck; 023 import org.jikesrvm.classloader.RVMField; 024 import org.jikesrvm.classloader.MemberReference; 025 import org.jikesrvm.classloader.RVMMethod; 026 import org.jikesrvm.classloader.RVMType; 027 import org.jikesrvm.classloader.TypeReference; 028 import org.jikesrvm.compilers.common.CompiledMethod; 029 import org.jikesrvm.compilers.common.CompiledMethods; 030 import org.jikesrvm.mm.mminterface.Barriers; 031 import org.jikesrvm.mm.mminterface.MemoryManager; 032 import org.jikesrvm.objectmodel.ObjectModel; 033 import org.jikesrvm.objectmodel.TIB; 034 import org.jikesrvm.scheduler.RVMThread; 035 import org.vmmagic.pragma.Entrypoint; 036 import org.vmmagic.pragma.Inline; 037 import org.vmmagic.pragma.NoInline; 038 import org.vmmagic.pragma.Pure; 039 import org.vmmagic.pragma.Uninterruptible; 040 import org.vmmagic.pragma.Unpreemptible; 041 import org.vmmagic.pragma.UnpreemptibleNoWarn; 042 import org.vmmagic.unboxed.Address; 043 import org.vmmagic.unboxed.Offset; 044 045 /** 046 * Entrypoints into the runtime of the virtual machine. 047 * 048 * <p> These are "helper functions" called from machine code 049 * emitted by BaselineCompilerImpl. 050 * They implement functionality that cannot be mapped directly 051 * into a small inline 052 * sequence of machine instructions. See also: Linker. 053 * 054 * <p> Note #1: If you add, remove, or change the signature of 055 * any of these methods you may need to change Entrypoints to match. 056 * 057 * <p> Note #2: Code here must be carefully written to be gc-safe 058 * while manipulating 059 * stackframe and instruction addresses. 060 * 061 * <p> Any time we are holding interior pointers to objects that 062 * could be moved by a garbage 063 * collection cycle we must either avoid passing through gc-sites 064 * (by writing 065 * straight line code with no "non-magic" method invocations) or we 066 * must turn off the 067 * collector (so that a gc request initiated by another thread will 068 * not run until we're 069 * done manipulating the bare pointers). Furthermore, while 070 * the collector is turned off, 071 * we must be careful not to make any allocation requests ("new"). 072 * 073 * <p> The interior pointers that we must worry about are: 074 * <ul> 075 * <li> "ip" values that point to interiors of "code" objects 076 * <li> "fp" values that point to interior of "stack" objects 077 * </ul> 078 */ 079 public class RuntimeEntrypoints implements Constants, ArchitectureSpecific.StackframeLayoutConstants { 080 081 private static final boolean traceAthrow = false; 082 // Trap codes for communication with C trap handler. 083 // 084 public static final int TRAP_UNKNOWN = -1; 085 public static final int TRAP_NULL_POINTER = 0; 086 public static final int TRAP_ARRAY_BOUNDS = 1; 087 public static final int TRAP_DIVIDE_BY_ZERO = 2; 088 public static final int TRAP_STACK_OVERFLOW = 3; 089 public static final int TRAP_CHECKCAST = 4; // opt-compiler 090 public static final int TRAP_REGENERATE = 5; // opt-compiler 091 public static final int TRAP_JNI_STACK = 6; // jni 092 public static final int TRAP_MUST_IMPLEMENT = 7; 093 public static final int TRAP_STORE_CHECK = 8; // opt-compiler 094 public static final int TRAP_STACK_OVERFLOW_FATAL = 9; // assertion checking 095 096 //---------------------------------------------------------------// 097 // Type Checking. // 098 //---------------------------------------------------------------// 099 100 /** 101 * Test if object is instance of target class/array or 102 * implements target interface. 103 * @param object object to be tested 104 * @param targetID type reference id corresponding to target 105 * class/array/interface 106 * @return true iff is object instance of target type? 107 */ 108 @Entrypoint 109 static boolean instanceOf(Object object, int targetID) throws NoClassDefFoundError { 110 111 /* Here, LHS and RHS refer to the way we would treat these if they were 112 arguments to an assignment operator and we were testing for 113 assignment-compatibility. In Java, "rhs instanceof lhs" means that 114 the operation "lhs = rhs" would succeed. This of course is backwards 115 if one is looking at it from the point of view of the "instanceof" 116 operator. */ 117 TypeReference tRef = TypeReference.getTypeRef(targetID); 118 RVMType lhsType = tRef.peekType(); 119 if (lhsType == null) { 120 lhsType = tRef.resolve(); 121 } 122 if (!lhsType.isResolved()) { 123 lhsType.resolve(); // forces loading/resolution of super class/interfaces 124 } 125 126 /* Test for null only AFTER we have resolved the type of targetID. */ 127 if (object == null) { 128 return false; // null is not an instance of any type 129 } 130 131 RVMType rhsType = ObjectModel.getObjectType(object); 132 /* RHS must already be resolved, since we have a non-null object that is 133 an instance of RHS */ 134 if (VM.VerifyAssertions) VM._assert(rhsType.isResolved()); 135 if (VM.VerifyAssertions) VM._assert(lhsType.isResolved()); 136 137 return lhsType == rhsType || DynamicTypeCheck.instanceOfResolved(lhsType, rhsType); 138 } 139 140 /** 141 * Throw exception unless object is instance of target 142 * class/array or implements target interface. 143 * @param object object to be tested 144 * @param id of type reference corresponding to target class/array/interface 145 */ 146 @Entrypoint 147 static void checkcast(Object object, int id) throws ClassCastException, NoClassDefFoundError { 148 if (object == null) { 149 return; // null may be cast to any type 150 } 151 152 TypeReference tRef = TypeReference.getTypeRef(id); 153 RVMType lhsType = tRef.peekType(); 154 if (lhsType == null) { 155 lhsType = tRef.resolve(); 156 } 157 RVMType rhsType = ObjectModel.getObjectType(object); 158 if (lhsType == rhsType) { 159 return; // exact match 160 } 161 162 // not an exact match, do more involved lookups 163 // 164 if (!isAssignableWith(lhsType, rhsType)) { 165 throw new ClassCastException("Cannot cast a(n) " + rhsType + " to a(n) " + lhsType); 166 } 167 } 168 169 /** 170 * Perform aastore bytecode 171 */ 172 @Entrypoint 173 static void aastore(Object[] arrayRef, int index, Object value) throws ArrayStoreException, ArrayIndexOutOfBoundsException { 174 checkstore(arrayRef, value); 175 int nelts = ObjectModel.getArrayLength(arrayRef); 176 if (index >=0 && index < nelts) { 177 Services.setArrayUninterruptible(arrayRef, index, value); 178 } else { 179 throw new ArrayIndexOutOfBoundsException(index); 180 } 181 } 182 183 /** 184 * Perform uninterruptible aastore bytecode 185 */ 186 @Entrypoint 187 @Uninterruptible 188 static void aastoreUninterruptible(Object[] arrayRef, int index, Object value) { 189 if (VM.VerifyAssertions) { 190 int nelts = ObjectModel.getArrayLength(arrayRef); 191 VM._assert(index >=0 && index < nelts); 192 } 193 Services.setArrayUninterruptible(arrayRef, index, value); 194 } 195 196 /** 197 * Throw exception iff array assignment is illegal. 198 */ 199 @Entrypoint 200 @Inline 201 static void checkstore(Object array, Object arrayElement) throws ArrayStoreException { 202 if (arrayElement == null) { 203 return; // null may be assigned to any type 204 } 205 206 RVMType lhsType = Magic.getObjectType(array); 207 RVMType elmType = lhsType.asArray().getElementType(); 208 209 if (elmType == RVMType.JavaLangObjectType) { 210 return; // array of Object can receive anything 211 } 212 213 RVMType rhsType = Magic.getObjectType(arrayElement); 214 215 if (elmType == rhsType) { 216 return; // exact type match 217 } 218 219 if (isAssignableWith(elmType, rhsType)) { 220 return; 221 } 222 223 throw new ArrayStoreException(); 224 } 225 226 /** 227 * May a variable of type "lhs" be assigned a value of type "rhs"? 228 * @param lhs type of variable 229 * @param rhs type of value 230 * @return true --> assignment is legal 231 * false --> assignment is illegal 232 * <strong>Assumption</strong>: caller has already tested "trivial" case 233 * (exact type match) 234 * so we need not repeat it here 235 */ 236 @Pure 237 @Inline(value=Inline.When.AllArgumentsAreConstant) 238 public static boolean isAssignableWith(RVMType lhs, RVMType rhs) { 239 if (!lhs.isResolved()) { 240 lhs.resolve(); 241 } 242 if (!rhs.isResolved()) { 243 rhs.resolve(); 244 } 245 return DynamicTypeCheck.instanceOfResolved(lhs, rhs); 246 } 247 248 //---------------------------------------------------------------// 249 // Object Allocation. // 250 //---------------------------------------------------------------// 251 252 /** 253 * Allocate something like "new Foo()". 254 * @param id id of type reference of class to create. 255 * @return object with header installed and all fields set to zero/null 256 * (ready for initializer to be run on it) 257 * See also: bytecode 0xbb ("new") 258 */ 259 @Entrypoint 260 static Object unresolvedNewScalar(int id, int site) throws NoClassDefFoundError, OutOfMemoryError { 261 TypeReference tRef = TypeReference.getTypeRef(id); 262 RVMType t = tRef.peekType(); 263 if (t == null) { 264 t = tRef.resolve(); 265 } 266 RVMClass cls = t.asClass(); 267 if (!cls.isInitialized()) { 268 initializeClassForDynamicLink(cls); 269 } 270 271 int allocator = MemoryManager.pickAllocator(cls); 272 int align = ObjectModel.getAlignment(cls); 273 int offset = ObjectModel.getOffsetForAlignment(cls, false); 274 return resolvedNewScalar(cls.getInstanceSize(), 275 cls.getTypeInformationBlock(), 276 cls.hasFinalizer(), 277 allocator, 278 align, 279 offset, 280 site); 281 } 282 283 /** 284 * Allocate something like "new Foo()". 285 * @param cls RVMClass of array to create 286 * @return object with header installed and all fields set to zero/null 287 * (ready for initializer to be run on it) 288 * See also: bytecode 0xbb ("new") 289 */ 290 public static Object resolvedNewScalar(RVMClass cls) { 291 292 int allocator = MemoryManager.pickAllocator(cls); 293 int site = MemoryManager.getAllocationSite(false); 294 int align = ObjectModel.getAlignment(cls); 295 int offset = ObjectModel.getOffsetForAlignment(cls, false); 296 return resolvedNewScalar(cls.getInstanceSize(), 297 cls.getTypeInformationBlock(), 298 cls.hasFinalizer(), 299 allocator, 300 align, 301 offset, 302 site); 303 } 304 305 /** 306 * Allocate something like "new Foo()". 307 * @param size size of object (including header), in bytes 308 * @param tib type information block for object 309 * @param hasFinalizer does this type have a finalizer? 310 * @param allocator int that encodes which allocator should be used 311 * @param align the alignment requested; must be a power of 2. 312 * @param offset the offset at which the alignment is desired. 313 * @param site the site id of the calling allocation site 314 * @return object with header installed and all fields set to zero/null 315 * (ready for initializer to be run on it) 316 * See also: bytecode 0xbb ("new") 317 */ 318 @Entrypoint 319 public static Object resolvedNewScalar(int size, TIB tib, boolean hasFinalizer, int allocator, int align, 320 int offset, int site) throws OutOfMemoryError { 321 322 // GC stress testing 323 if (VM.ForceFrequentGC) checkAllocationCountDownToGC(); 324 325 // Allocate the object and initialize its header 326 Object newObj = MemoryManager.allocateScalar(size, tib, allocator, align, offset, site); 327 328 // Deal with finalization 329 if (hasFinalizer) MemoryManager.addFinalizer(newObj); 330 331 return newObj; 332 } 333 334 /** 335 * Allocate something like "new Foo[]". 336 * @param numElements number of array elements 337 * @param id id of type reference of array to create. 338 * @param site the site id of the calling allocation site 339 * @return array with header installed and all fields set to zero/null 340 * See also: bytecode 0xbc ("anewarray") 341 */ 342 @Entrypoint 343 public static Object unresolvedNewArray(int numElements, int id, int site) 344 throws NoClassDefFoundError, OutOfMemoryError, NegativeArraySizeException { 345 TypeReference tRef = TypeReference.getTypeRef(id); 346 RVMType t = tRef.peekType(); 347 if (t == null) { 348 t = tRef.resolve(); 349 } 350 RVMArray array = t.asArray(); 351 if (!array.isInitialized()) { 352 array.resolve(); 353 array.instantiate(); 354 } 355 356 return resolvedNewArray(numElements, array, site); 357 } 358 359 /** 360 * Allocate something like "new Foo[]". 361 * @param numElements number of array elements 362 * @param array RVMArray of array to create 363 * @return array with header installed and all fields set to zero/null 364 * See also: bytecode 0xbc ("anewarray") 365 */ 366 public static Object resolvedNewArray(int numElements, RVMArray array) 367 throws OutOfMemoryError, NegativeArraySizeException { 368 return resolvedNewArray(numElements, array, MemoryManager.getAllocationSite(false)); 369 } 370 371 public static Object resolvedNewArray(int numElements, RVMArray array, int site) 372 throws OutOfMemoryError, NegativeArraySizeException { 373 374 return resolvedNewArray(numElements, 375 array.getLogElementSize(), 376 ObjectModel.computeArrayHeaderSize(array), 377 array.getTypeInformationBlock(), 378 MemoryManager.pickAllocator(array), 379 ObjectModel.getAlignment(array), 380 ObjectModel.getOffsetForAlignment(array, false), 381 site); 382 } 383 384 /** 385 * Allocate something like "new int[cnt]" or "new Foo[cnt]". 386 * @param numElements number of array elements 387 * @param logElementSize size in bytes of an array element, log base 2. 388 * @param headerSize size in bytes of array header 389 * @param tib type information block for array object 390 * @param allocator int that encodes which allocator should be used 391 * @param align the alignment requested; must be a power of 2. 392 * @param offset the offset at which the alignment is desired. 393 * @return array object with header installed and all elements set 394 * to zero/null 395 * See also: bytecode 0xbc ("newarray") and 0xbd ("anewarray") 396 */ 397 @Entrypoint 398 public static Object resolvedNewArray(int numElements, int logElementSize, int headerSize, TIB tib, 399 int allocator, int align, int offset, int site) 400 throws OutOfMemoryError, NegativeArraySizeException { 401 402 if (numElements < 0) raiseNegativeArraySizeException(); 403 404 // GC stress testing 405 if (VM.ForceFrequentGC) checkAllocationCountDownToGC(); 406 407 // Allocate the array and initialize its header 408 return MemoryManager.allocateArray(numElements, logElementSize, headerSize, tib, allocator, align, offset, site); 409 } 410 411 /** 412 * Clone a Scalar or Array Object. 413 * called from java/lang/Object.clone(). 414 * <p> 415 * For simplicity, we just code this more or less in Java using 416 * internal reflective operations and some magic. 417 * This is inefficient for large scalar objects, but until that 418 * is proven to be a performance problem, we won't worry about it. 419 * By keeping this in Java instead of dropping into Memory.copy, 420 * we avoid having to add special case code to deal with write barriers, 421 * and other such things. 422 * <p> 423 * This method calls specific cloning routines based on type to help 424 * guide the inliner (which won't inline a single large method). 425 * 426 * @param obj the object to clone 427 * @return the cloned object 428 */ 429 public static Object clone(Object obj) throws OutOfMemoryError, CloneNotSupportedException { 430 RVMType type = Magic.getObjectType(obj); 431 if (type.isArrayType()) { 432 return cloneArray(obj, type); 433 } else { 434 return cloneClass(obj, type); 435 } 436 } 437 438 /** 439 * Clone an array 440 * 441 * @param obj the array to clone 442 * @param type the type information for the array 443 * @return the cloned object 444 */ 445 private static Object cloneArray(Object obj, RVMType type) throws OutOfMemoryError { 446 RVMArray ary = type.asArray(); 447 int nelts = ObjectModel.getArrayLength(obj); 448 Object newObj = resolvedNewArray(nelts, ary); 449 System.arraycopy(obj, 0, newObj, 0, nelts); 450 return newObj; 451 } 452 453 /** 454 * Clone an object implementing a class - check that the class is cloneable 455 * (we make this a small method with just a test so that the inliner will 456 * inline it and hopefully eliminate the instanceof test). 457 * 458 * @param obj the object to clone 459 * @param type the type information for the class 460 * @return the cloned object 461 */ 462 private static Object cloneClass(Object obj, RVMType type) throws OutOfMemoryError, CloneNotSupportedException { 463 if (!(obj instanceof Cloneable)) { 464 throw new CloneNotSupportedException(); 465 } else { 466 return cloneClass2(obj, type); 467 } 468 } 469 470 /** 471 * Clone an object implementing a class - the actual clone 472 * 473 * @param obj the object to clone 474 * @param type the type information for the class 475 * @return the cloned object 476 */ 477 private static Object cloneClass2(Object obj, RVMType type) throws OutOfMemoryError { 478 RVMClass cls = type.asClass(); 479 Object newObj = resolvedNewScalar(cls); 480 for (RVMField f : cls.getInstanceFields()) { 481 if (f.isReferenceType()) { 482 // Writing a reference 483 // Do via slower "VM-internal reflection" to enable 484 // collectors to do the right thing wrt reference counting 485 // and write barriers. 486 f.setObjectValueUnchecked(newObj, f.getObjectValueUnchecked(obj)); 487 } else { 488 // Primitive type 489 // Check if we need to go via the slower barried path 490 TypeReference fieldType = f.getType(); 491 if (Barriers.NEEDS_BOOLEAN_PUTFIELD_BARRIER && fieldType.isBooleanType()) { 492 f.setBooleanValueUnchecked(newObj, f.getBooleanValueUnchecked(obj)); 493 continue; 494 } else if (Barriers.NEEDS_BYTE_PUTFIELD_BARRIER && fieldType.isByteType()) { 495 f.setByteValueUnchecked(newObj, f.getByteValueUnchecked(obj)); 496 continue; 497 } else if (Barriers.NEEDS_CHAR_PUTFIELD_BARRIER && fieldType.isCharType()) { 498 f.setCharValueUnchecked(newObj, f.getCharValueUnchecked(obj)); 499 continue; 500 } else if (Barriers.NEEDS_DOUBLE_PUTFIELD_BARRIER && fieldType.isDoubleType()) { 501 f.setDoubleValueUnchecked(newObj, f.getDoubleValueUnchecked(obj)); 502 continue; 503 } else if (Barriers.NEEDS_FLOAT_PUTFIELD_BARRIER && fieldType.isFloatType()) { 504 f.setFloatValueUnchecked(newObj, f.getFloatValueUnchecked(obj)); 505 continue; 506 } else if (Barriers.NEEDS_INT_PUTFIELD_BARRIER && fieldType.isIntType()) { 507 f.setIntValueUnchecked(newObj, f.getIntValueUnchecked(obj)); 508 continue; 509 } else if (Barriers.NEEDS_LONG_PUTFIELD_BARRIER && fieldType.isLongType()) { 510 f.setLongValueUnchecked(newObj, f.getLongValueUnchecked(obj)); 511 continue; 512 } else if (Barriers.NEEDS_SHORT_PUTFIELD_BARRIER && fieldType.isShortType()) { 513 f.setShortValueUnchecked(newObj, f.getShortValueUnchecked(obj)); 514 continue; 515 } else if (Barriers.NEEDS_WORD_PUTFIELD_BARRIER && fieldType.isWordType()) { 516 f.setWordValueUnchecked(newObj, f.getWordValueUnchecked(obj)); 517 continue; 518 } else if (Barriers.NEEDS_ADDRESS_PUTFIELD_BARRIER && fieldType.isAddressType()) { 519 f.setAddressValueUnchecked(newObj, f.getAddressValueUnchecked(obj)); 520 continue; 521 } else if (Barriers.NEEDS_EXTENT_PUTFIELD_BARRIER && fieldType.isExtentType()) { 522 f.setExtentValueUnchecked(newObj, f.getExtentValueUnchecked(obj)); 523 continue; 524 } else if (Barriers.NEEDS_OFFSET_PUTFIELD_BARRIER && fieldType.isOffsetType()) { 525 f.setOffsetValueUnchecked(newObj, f.getOffsetValueUnchecked(obj)); 526 continue; 527 } else { 528 // Can perform raw copy of field 529 int size = f.getSize(); 530 Offset offset = f.getOffset(); 531 if (VM.BuildFor32Addr) { 532 // As per pre primitive write barrier code we test the most likely 533 // case first 534 if (size == BYTES_IN_INT) { 535 int bits = Magic.getIntAtOffset(obj, offset); 536 Magic.setIntAtOffset(newObj, offset, bits); 537 continue; 538 } else if (size == BYTES_IN_LONG) { 539 long bits = Magic.getLongAtOffset(obj, offset); 540 Magic.setLongAtOffset(newObj, offset, bits); 541 continue; 542 } 543 } else { 544 // BuildFor64Addr 545 // As per pre primitive write barrier code we test the most likely 546 // case first 547 if (size == BYTES_IN_LONG) { 548 long bits = Magic.getLongAtOffset(obj, offset); 549 Magic.setLongAtOffset(newObj, offset, bits); 550 continue; 551 } else if (size == BYTES_IN_INT) { 552 int bits = Magic.getIntAtOffset(obj, offset); 553 Magic.setIntAtOffset(newObj, offset, bits); 554 continue; 555 } 556 } 557 if (size == BYTES_IN_CHAR) { 558 char bits = Magic.getCharAtOffset(obj, offset); 559 Magic.setCharAtOffset(newObj, offset, bits); 560 } else { 561 if (VM.VerifyAssertions) VM._assert(size == BYTES_IN_BYTE); 562 byte bits = Magic.getByteAtOffset(obj, offset); 563 Magic.setByteAtOffset(newObj, offset, bits); 564 } 565 } 566 } 567 } 568 return newObj; 569 } 570 571 /** 572 * Helper function to actually throw the required exception. 573 * Keep out of line to mitigate code space when quickNewArray is inlined. 574 */ 575 @NoInline 576 private static void raiseNegativeArraySizeException() throws NegativeArraySizeException { 577 throw new NegativeArraySizeException(); 578 } 579 580 /** 581 * Get an object's "hashcode" value. 582 * 583 * Side effect: hash value is generated and stored into object's 584 * status word. 585 * 586 * @return object's hashcode. 587 * @see java.lang.Object#hashCode(). 588 */ 589 public static int getObjectHashCode(Object object) { 590 return ObjectModel.getObjectHashCode(object); 591 } 592 593 //---------------------------------------------------------------// 594 // Dynamic linking. // 595 //---------------------------------------------------------------// 596 597 /** 598 * Prepare a class for use prior to first allocation, 599 * field access, or method invocation. 600 * Made public so that it is accessible from java.lang.reflect.*. 601 * @see MemberReference#needsDynamicLink 602 */ 603 public static void initializeClassForDynamicLink(RVMClass cls) { 604 if (VM.TraceClassLoading) { 605 VM.sysWrite("RuntimeEntrypoints.initializeClassForDynamicLink: (begin) " + cls + "\n"); 606 } 607 608 cls.resolve(); 609 cls.instantiate(); 610 cls.initialize(); // throws ExceptionInInitializerError 611 612 if (VM.TraceClassLoading) { 613 VM.sysWrite("RuntimeEntrypoints.initializeClassForDynamicLink: (end) " + cls + "\n"); 614 } 615 } 616 617 //---------------------------------------------------------------// 618 // Implementation Errors. // 619 //---------------------------------------------------------------// 620 621 /** 622 * Report unexpected method call: interface method 623 * (virtual machine dispatching error, shouldn't happen). 624 */ 625 static void unexpectedInterfaceMethodCall() { 626 VM.sysFail("interface method dispatching error"); 627 } 628 629 /** 630 * Report unexpected method call: abstract method (verification error). 631 */ 632 @Entrypoint 633 static void unexpectedAbstractMethodCall() { 634 VM.sysWrite("RuntimeEntrypoints.unexpectedAbstractMethodCall\n"); 635 throw new AbstractMethodError(); 636 } 637 638 //---------------------------------------------------------------// 639 // Exception Handling. // 640 //---------------------------------------------------------------// 641 642 /** 643 * Deliver a software exception to current java thread. 644 * @param exceptionObject exception object to deliver 645 * (null --> deliver NullPointerException). 646 * does not return 647 * (stack is unwound and execution resumes in a catch block) 648 * 649 * This method is public so that it can be invoked by java.lang.VMClass. 650 */ 651 @NoInline 652 @Entrypoint 653 @Unpreemptible("Deliver exception possibly from unpreemptible code") 654 public static void athrow(Throwable exceptionObject) { 655 if (traceAthrow) { 656 VM.sysWriteln("in athrow."); 657 RVMThread.dumpStack(); 658 } 659 RVMThread myThread = RVMThread.getCurrentThread(); 660 Registers exceptionRegisters = myThread.getExceptionRegisters(); 661 VM.disableGC(); // VM.enableGC() is called when the exception is delivered. 662 Magic.saveThreadState(exceptionRegisters); 663 exceptionRegisters.inuse = true; 664 deliverException(exceptionObject, exceptionRegisters); 665 } 666 667 /** 668 * Deliver a hardware exception to current java thread. 669 * <p> 670 * Does not return. 671 * (stack is unwound, starting at trap site, and 672 * execution resumes in a catch block somewhere up the stack) 673 * /or/ execution resumes at instruction following trap 674 * (for TRAP_STACK_OVERFLOW) 675 * 676 * <p> Note: Control reaches here by the actions of an 677 * external "C" signal handler 678 * which saves the register state of the trap site into the 679 * "exceptionRegisters" field of the current 680 * Thread object. 681 * The signal handler also inserts a <hardware trap> frame 682 * onto the stack immediately above this frame, for use by 683 * HardwareTrapGCMapIterator during garbage collection. 684 * 685 * @param trapCode code indicating kind of exception that was trapped 686 * (see TRAP_xxx, above) 687 * @param trapInfo array subscript (for array bounds trap, only) 688 */ 689 @Entrypoint 690 @UnpreemptibleNoWarn 691 static void deliverHardwareException(int trapCode, int trapInfo) { 692 if (false) VM.sysWriteln("delivering hardware exception"); 693 RVMThread myThread = RVMThread.getCurrentThread(); 694 if (false) VM.sysWriteln("we have a thread = ",Magic.objectAsAddress(myThread)); 695 if (false) VM.sysWriteln("it's in state = ",myThread.getExecStatus()); 696 Registers exceptionRegisters = myThread.getExceptionRegisters(); 697 if (false) VM.sysWriteln("we have exception registers = ",Magic.objectAsAddress(exceptionRegisters)); 698 699 if ((trapCode == TRAP_STACK_OVERFLOW || trapCode == TRAP_JNI_STACK) && 700 myThread.getStack().length < (STACK_SIZE_MAX >> LOG_BYTES_IN_ADDRESS) && 701 !myThread.hasNativeStackFrame()) { 702 // expand stack by the size appropriate for normal or native frame 703 // and resume execution at successor to trap instruction 704 // (C trap handler has set register.ip to the instruction following the trap). 705 if (trapCode == TRAP_JNI_STACK) { 706 RVMThread.resizeCurrentStack(myThread.getStackLength() + STACK_SIZE_JNINATIVE_GROW, exceptionRegisters); 707 } else { 708 RVMThread.resizeCurrentStack(myThread.getStackLength() + STACK_SIZE_GROW, exceptionRegisters); 709 } 710 if (VM.VerifyAssertions) VM._assert(exceptionRegisters.inuse); 711 exceptionRegisters.inuse = false; 712 Magic.restoreHardwareExceptionState(exceptionRegisters); 713 714 if (VM.VerifyAssertions) VM._assert(NOT_REACHED); 715 } 716 717 // GC stress testing 718 if (canForceGC()) { 719 //VM.sysWrite("FORCING GC: in deliverHardwareException\n"); 720 System.gc(); 721 } 722 723 // Sanity checking. 724 // Hardware traps in uninterruptible code should be considered hard failures. 725 if (!VM.sysFailInProgress()) { 726 Address fp = exceptionRegisters.getInnermostFramePointer(); 727 int compiledMethodId = Magic.getCompiledMethodID(fp); 728 if (compiledMethodId != INVISIBLE_METHOD_ID) { 729 CompiledMethod compiledMethod = CompiledMethods.getCompiledMethod(compiledMethodId); 730 Address ip = exceptionRegisters.getInnermostInstructionAddress(); 731 Offset instructionOffset = compiledMethod.getInstructionOffset(ip); 732 if (compiledMethod.isWithinUninterruptibleCode(instructionOffset)) { 733 switch (trapCode) { 734 case TRAP_NULL_POINTER: 735 VM.sysWriteln("\nFatal error: NullPointerException within uninterruptible region."); 736 break; 737 case TRAP_ARRAY_BOUNDS: 738 VM.sysWriteln("\nFatal error: ArrayIndexOutOfBoundsException within uninterruptible region (index was ", trapInfo, ")."); 739 break; 740 case TRAP_DIVIDE_BY_ZERO: 741 VM.sysWriteln("\nFatal error: DivideByZero within uninterruptible region."); 742 break; 743 case TRAP_STACK_OVERFLOW: 744 case TRAP_JNI_STACK: 745 VM.sysWriteln("\nFatal error: StackOverflowError within uninterruptible region."); 746 break; 747 case TRAP_CHECKCAST: 748 VM.sysWriteln("\nFatal error: ClassCastException within uninterruptible region."); 749 break; 750 case TRAP_MUST_IMPLEMENT: 751 VM.sysWriteln("\nFatal error: IncompatibleClassChangeError within uninterruptible region."); 752 break; 753 case TRAP_STORE_CHECK: 754 VM.sysWriteln("\nFatal error: ArrayStoreException within uninterruptible region."); 755 break; 756 default: 757 VM.sysWriteln("\nFatal error: Unknown hardware trap within uninterruptible region."); 758 break; 759 } 760 VM.sysFail("Exiting virtual machine due to uninterruptibility violation."); 761 } 762 } 763 } 764 765 Throwable exceptionObject; 766 switch (trapCode) { 767 case TRAP_NULL_POINTER: 768 exceptionObject = new java.lang.NullPointerException(); 769 break; 770 case TRAP_ARRAY_BOUNDS: 771 exceptionObject = new java.lang.ArrayIndexOutOfBoundsException(trapInfo); 772 break; 773 case TRAP_DIVIDE_BY_ZERO: 774 exceptionObject = new java.lang.ArithmeticException(); 775 break; 776 case TRAP_STACK_OVERFLOW: 777 case TRAP_JNI_STACK: 778 exceptionObject = new java.lang.StackOverflowError(); 779 break; 780 case TRAP_CHECKCAST: 781 exceptionObject = new java.lang.ClassCastException(); 782 break; 783 case TRAP_MUST_IMPLEMENT: 784 exceptionObject = new java.lang.IncompatibleClassChangeError(); 785 break; 786 case TRAP_STORE_CHECK: 787 exceptionObject = new java.lang.ArrayStoreException(); 788 break; 789 default: 790 exceptionObject = new java.lang.UnknownError(); 791 RVMThread.traceback("UNKNOWN ERROR"); 792 break; 793 } 794 795 VM.disableGC(); // VM.enableGC() is called when the exception is delivered. 796 deliverException(exceptionObject, exceptionRegisters); 797 } 798 799 /** 800 * Unlock an object and then deliver a software exception 801 * to current java thread. 802 * <p> 803 * Does not return (stack is unwound and execution resumes in a catch block). 804 * 805 * @param objToUnlock object to unlock 806 * @param objToThrow exception object to deliver 807 * ({@code null} --> deliver NullPointerException). 808 */ 809 @NoInline 810 @Entrypoint 811 static void unlockAndThrow(Object objToUnlock, Throwable objToThrow) { 812 ObjectModel.genericUnlock(objToUnlock); 813 athrow(objToThrow); 814 } 815 816 /** 817 * Create and throw a java.lang.ArrayIndexOutOfBoundsException. 818 * Only used in some configurations where it is easier to make a call 819 * then recover the array index from a trap instruction. 820 */ 821 @NoInline 822 @Entrypoint 823 static void raiseArrayIndexOutOfBoundsException(int index) { 824 throw new java.lang.ArrayIndexOutOfBoundsException(index); 825 } 826 827 /** 828 * Create and throw a java.lang.ArrayIndexOutOfBoundsException. 829 * Used (rarely) by the opt compiler when it has determined that 830 * an array access will unconditionally raise an array bounds check 831 * error, but it has lost track of exactly what the index is going to be. 832 */ 833 @NoInline 834 static void raiseArrayIndexOutOfBoundsException() { 835 throw new java.lang.ArrayIndexOutOfBoundsException(); 836 } 837 838 /** 839 * Create and throw a java.lang.NullPointerException. 840 * Used in a few circumstances to reduce code space costs 841 * of inlining (see java.lang.System.arraycopy()). Could also 842 * be used to raise a null pointer exception without going through 843 * the hardware trap handler; currently this is only done when the 844 * opt compiler has determined that an instruction will unconditionally 845 * raise a null pointer exception. 846 */ 847 @NoInline 848 @Entrypoint 849 public static void raiseNullPointerException() { 850 throw new java.lang.NullPointerException(); 851 } 852 853 /** 854 * Create and throw a java.lang.ArrayStoreException. 855 * Used in a few circumstances to reduce code space costs 856 * of inlining (see java.lang.System.arraycopy()). 857 */ 858 @NoInline 859 public static void raiseArrayStoreException() { 860 throw new java.lang.ArrayStoreException(); 861 } 862 863 /** 864 * Create and throw a java.lang.ArithmeticException. 865 * Used to raise an arithmetic exception without going through 866 * the hardware trap handler; currently this is only done when the 867 * opt compiler has determined that an instruction will unconditionally 868 * raise an arithmetic exception. 869 */ 870 @NoInline 871 @Entrypoint 872 static void raiseArithmeticException() { 873 throw new java.lang.ArithmeticException(); 874 } 875 876 /** 877 * Create and throw a java.lang.AbstractMethodError. 878 * Used to handle error cases in invokeinterface dispatching. 879 */ 880 @NoInline 881 @Entrypoint 882 static void raiseAbstractMethodError() { 883 throw new java.lang.AbstractMethodError(); 884 } 885 886 /** 887 * Create and throw a java.lang.IllegalAccessError. 888 * Used to handle error cases in invokeinterface dispatching. 889 */ 890 @NoInline 891 @Entrypoint 892 static void raiseIllegalAccessError() { 893 throw new java.lang.IllegalAccessError(); 894 } 895 896 //----------------// 897 // implementation // 898 //----------------// 899 900 public static void init() { 901 // tell "RunBootImage.C" to pass control to 902 // "RuntimeEntrypoints.deliverHardwareException()" 903 // whenever the host operating system detects a hardware trap 904 // 905 BootRecord.the_boot_record.hardwareTrapMethodId = CompiledMethods.createHardwareTrapCompiledMethod().getId(); 906 BootRecord.the_boot_record.deliverHardwareExceptionOffset = 907 Entrypoints.deliverHardwareExceptionMethod.getOffset(); 908 909 // tell "RunBootImage.C" to set "RVMThread.debugRequested" flag 910 // whenever the host operating system detects a debug request signal 911 // 912 BootRecord.the_boot_record.debugRequestedOffset = Entrypoints.debugRequestedField.getOffset(); 913 } 914 915 /** 916 * Build a multi-dimensional array. 917 * @param methodId TODO document me 918 * @param numElements number of elements to allocate for each dimension 919 * @param arrayType type of array that will result 920 * @return array object 921 */ 922 public static Object buildMultiDimensionalArray(int methodId, int[] numElements, RVMArray arrayType) { 923 RVMMethod method = MemberReference.getMemberRef(methodId).asMethodReference().peekResolvedMethod(); 924 if (VM.VerifyAssertions) VM._assert(method != null); 925 return buildMDAHelper(method, numElements, 0, arrayType); 926 } 927 928 /** 929 * Build a two-dimensional array. 930 * @param methodId TODO document me 931 * @param dim0 the arraylength for arrays in dimension 0 932 * @param dim1 the arraylength for arrays in dimension 1 933 * @param arrayType type of array that will result 934 * @return array object 935 */ 936 public static Object buildTwoDimensionalArray(int methodId, int dim0, int dim1, RVMArray arrayType) { 937 RVMMethod method = MemberReference.getMemberRef(methodId).asMethodReference().peekResolvedMethod(); 938 if (VM.VerifyAssertions) VM._assert(method != null); 939 940 if (!arrayType.isInstantiated()) { 941 arrayType.resolve(); 942 arrayType.instantiate(); 943 } 944 945 Object[] newArray = (Object[])resolvedNewArray(dim0, arrayType); 946 947 RVMArray innerArrayType = arrayType.getElementType().asArray(); 948 if (!innerArrayType.isInstantiated()) { 949 innerArrayType.resolve(); 950 innerArrayType.instantiate(); 951 } 952 953 for (int i=0; i<dim0; i++) { 954 newArray[i] = resolvedNewArray(dim1, innerArrayType); 955 } 956 957 return newArray; 958 } 959 960 /** 961 * @param method Apparently unused (!) 962 * @param numElements Number of elements to allocate for each dimension 963 * @param dimIndex Current dimension to build 964 * @param arrayType type of array that will result 965 */ 966 public static Object buildMDAHelper(RVMMethod method, int[] numElements, int dimIndex, RVMArray arrayType) { 967 968 if (!arrayType.isInstantiated()) { 969 arrayType.resolve(); 970 arrayType.instantiate(); 971 } 972 973 int nelts = numElements[dimIndex]; 974 Object newObject = resolvedNewArray(nelts, arrayType); 975 976 if (++dimIndex == numElements.length) { 977 return newObject; // all dimensions have been built 978 } 979 980 Object[] newArray = (Object[]) newObject; 981 RVMArray newArrayType = arrayType.getElementType().asArray(); 982 983 for (int i = 0; i < nelts; ++i) { 984 newArray[i] = buildMDAHelper(method, numElements, dimIndex, newArrayType); 985 } 986 987 return newArray; 988 } 989 990 /** 991 * Deliver an exception to current java thread. 992 * <STRONG> Precondition: </STRONG> VM.disableGC has already been called. 993 * <ol> 994 * <li> exceptionRegisters may not match any reasonable stack 995 * frame at this point. 996 * <li> we're going to be playing with raw addresses (fp, ip). 997 * </ol> 998 * <p> 999 * Does not return: 1000 * <ul> 1001 * <li> stack is unwound and execution resumes in a catch block 1002 * <li> <em> or </em> current thread is terminated if no catch block is found 1003 * </ul> 1004 1005 * @param exceptionObject exception object to deliver 1006 * @param exceptionRegisters register state corresponding to exception site 1007 */ 1008 @Unpreemptible("Deliver exception trying to avoid preemption") 1009 private static void deliverException(Throwable exceptionObject, Registers exceptionRegisters) { 1010 if (VM.TraceExceptionDelivery) { 1011 VM.sysWriteln("RuntimeEntrypoints.deliverException() entered; just got an exception object."); 1012 } 1013 //VM.sysWriteln("throwing exception!"); 1014 //RVMThread.dumpStack(); 1015 1016 // walk stack and look for a catch block 1017 // 1018 if (VM.TraceExceptionDelivery) { 1019 VM.sysWrite("Hunting for a catch block..."); 1020 } 1021 RVMType exceptionType = Magic.getObjectType(exceptionObject); 1022 Address fp = exceptionRegisters.getInnermostFramePointer(); 1023 Address hijackedCalleeFp = RVMThread.getCurrentThread().getHijackedReturnCalleeFp(); 1024 boolean leapfroggedReturnBarrier = false; 1025 if (VM.VerifyAssertions) VM._assert(hijackedCalleeFp.isZero() || hijackedCalleeFp.GE(fp)); 1026 while (Magic.getCallerFramePointer(fp).NE(STACKFRAME_SENTINEL_FP)) { 1027 if (!hijackedCalleeFp.isZero() && hijackedCalleeFp.LE(fp)) { 1028 leapfroggedReturnBarrier = true; 1029 } 1030 int compiledMethodId = Magic.getCompiledMethodID(fp); 1031 if (compiledMethodId != INVISIBLE_METHOD_ID) { 1032 CompiledMethod compiledMethod = CompiledMethods.getCompiledMethod(compiledMethodId); 1033 ExceptionDeliverer exceptionDeliverer = compiledMethod.getExceptionDeliverer(); 1034 Address ip = exceptionRegisters.getInnermostInstructionAddress(); 1035 Offset ipOffset = compiledMethod.getInstructionOffset(ip); 1036 int catchBlockOffset = compiledMethod.findCatchBlockForInstruction(ipOffset, exceptionType); 1037 1038 if (catchBlockOffset >= 0) { 1039 // found an appropriate catch block 1040 if (VM.TraceExceptionDelivery) { 1041 VM.sysWriteln("found one; delivering."); 1042 } 1043 if (leapfroggedReturnBarrier) { 1044 RVMThread t = RVMThread.getCurrentThread(); 1045 if (RVMThread.DEBUG_STACK_TRAMPOLINE) VM.sysWriteln("leapfrogged..."); 1046 t.deInstallStackTrampoline(); 1047 } 1048 Address catchBlockStart = compiledMethod.getInstructionAddress(Offset.fromIntSignExtend(catchBlockOffset)); 1049 exceptionDeliverer.deliverException(compiledMethod, catchBlockStart, exceptionObject, exceptionRegisters); 1050 if (VM.VerifyAssertions) VM._assert(NOT_REACHED); 1051 } 1052 1053 exceptionDeliverer.unwindStackFrame(compiledMethod, exceptionRegisters); 1054 } else { 1055 unwindInvisibleStackFrame(exceptionRegisters); 1056 } 1057 fp = exceptionRegisters.getInnermostFramePointer(); 1058 } 1059 1060 if (VM.TraceExceptionDelivery) { 1061 VM.sysWriteln("Nope."); 1062 VM.sysWriteln("RuntimeEntrypoints.deliverException() found no catch block."); 1063 } 1064 /* No appropriate catch block found. */ 1065 if (RVMThread.DEBUG_STACK_TRAMPOLINE && leapfroggedReturnBarrier) VM.sysWriteln("Leapfrogged, and unhandled!"); 1066 handleUncaughtException(exceptionObject); 1067 } 1068 1069 @UnpreemptibleNoWarn("Uncaught exception handling that may cause preemption") 1070 private static void handleUncaughtException(Throwable exceptionObject) { 1071 RVMThread.getCurrentThread().handleUncaughtException(exceptionObject); 1072 } 1073 1074 /** 1075 * Skip over all frames below currfp with saved code pointers outside of heap 1076 * (C frames), stopping at the native frame immediately preceding the glue 1077 * frame which contains the method ID of the native method (this is necessary 1078 * to allow retrieving the return address of the glue frame). 1079 * 1080 * @param currfp The current frame is expected to be one of the JNI functions 1081 * called from C, below which is one or more native stack frames 1082 */ 1083 @Uninterruptible 1084 public static Address unwindNativeStackFrame(Address currfp) { 1085 if (VM.BuildForIA32) { 1086 return currfp; 1087 } 1088 // Remembered address of previous FP 1089 Address callee_fp; 1090 // Address of native frame 1091 Address fp = Magic.getCallerFramePointer(currfp); 1092 // Instruction pointer for current native frame 1093 Address ip; 1094 1095 // Loop until either we fall off the stack or we find an instruction address 1096 // in one of our heaps 1097 do { 1098 callee_fp = fp; 1099 ip = Magic.getReturnAddressUnchecked(fp); 1100 fp = Magic.getCallerFramePointer(fp); 1101 } while (!MemoryManager.addressInVM(ip) && fp.NE(STACKFRAME_SENTINEL_FP)); 1102 1103 if (VM.BuildForPowerPC) { 1104 // We want to return fp, not callee_fp because we want the stack walkers 1105 // to see the "mini-frame" which has the RVM information, not the "main frame" 1106 // pointed to by callee_fp which is where the saved ip was actually stored. 1107 return fp; 1108 } else { 1109 return callee_fp; 1110 } 1111 } 1112 1113 /** 1114 * The current frame is expected to be one of the JNI functions 1115 * called from C, 1116 * below which is one or more native stack frames. 1117 * Skip over all frames below which do not contain any object 1118 * references. 1119 */ 1120 @Uninterruptible 1121 public static Address unwindNativeStackFrameForGC(Address currfp) { 1122 return unwindNativeStackFrame(currfp); 1123 } 1124 1125 /** 1126 * Unwind stack frame for an <invisible method>. 1127 * See also: ExceptionDeliverer.unwindStackFrame() 1128 * <p> 1129 * !!TODO: Could be a reflective method invoker frame. 1130 * Does it clobber any non-volatiles? 1131 * If so, how do we restore them? 1132 * (I don't think our current implementations of reflective method 1133 * invokers save/restore any nonvolatiles, so we're probably ok. 1134 * --dave 6/29/01 1135 */ 1136 @Uninterruptible 1137 private static void unwindInvisibleStackFrame(Registers registers) { 1138 registers.unwindStackFrame(); 1139 } 1140 1141 /** 1142 * Number of allocations left before a GC is forced. Only used if VM.StressGCAllocationInterval is not 0. 1143 */ 1144 static int allocationCountDownToGC = VM.StressGCAllocationInterval; 1145 1146 /** 1147 * Number of c-to-java jni calls left before a GC is forced. Only used if VM.StressGCAllocationInterval is not 0. 1148 */ 1149 static int jniCountDownToGC = VM.StressGCAllocationInterval; 1150 1151 /** 1152 * Check to see if we are stress testing garbage collector and if another JNI call should 1153 * trigger a gc then do so. 1154 */ 1155 @Inline 1156 public static void checkJNICountDownToGC() { 1157 // Temporarily disabled as it will causes nightly to take too long to run 1158 // There should be a mechanism to optionally enable this countdown in Configuration 1159 if (false && canForceGC()) { 1160 if (jniCountDownToGC-- <= 0) { 1161 jniCountDownToGC = VM.StressGCAllocationInterval; 1162 System.gc(); 1163 } 1164 } 1165 } 1166 1167 /** 1168 * Check to see if we are stress testing garbage collector and if another allocation should 1169 * trigger a GC then do so. 1170 */ 1171 @Inline 1172 private static void checkAllocationCountDownToGC() { 1173 if (canForceGC()) { 1174 if (allocationCountDownToGC-- <= 0) { 1175 allocationCountDownToGC = VM.StressGCAllocationInterval; 1176 System.gc(); 1177 } 1178 } 1179 } 1180 1181 /** 1182 * Return {@code true} if we are stress testing garbage collector and the system is in state where we 1183 * can force a garbage collection. 1184 */ 1185 @Inline 1186 @Uninterruptible 1187 private static boolean canForceGC() { 1188 return VM.ForceFrequentGC && RVMThread.safeToForceGCs() && MemoryManager.collectionEnabled(); 1189 } 1190 }