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 */ 013package org.jikesrvm.mm.mminterface; 014 015import static org.jikesrvm.HeapLayoutConstants.BOOT_IMAGE_CODE_SIZE; 016import static org.jikesrvm.HeapLayoutConstants.BOOT_IMAGE_CODE_START; 017import static org.jikesrvm.HeapLayoutConstants.BOOT_IMAGE_DATA_SIZE; 018import static org.jikesrvm.HeapLayoutConstants.BOOT_IMAGE_DATA_START; 019import static org.jikesrvm.objectmodel.TIBLayoutConstants.IMT_METHOD_SLOTS; 020import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG; 021import static org.mmtk.utility.Constants.MIN_ALIGNMENT; 022 023import java.lang.ref.PhantomReference; 024import java.lang.ref.SoftReference; 025import java.lang.ref.WeakReference; 026 027import org.jikesrvm.VM; 028import org.jikesrvm.classloader.RVMArray; 029import org.jikesrvm.classloader.RVMClass; 030import org.jikesrvm.classloader.RVMMethod; 031import org.jikesrvm.classloader.RVMType; 032import org.jikesrvm.classloader.SpecializedMethod; 033import org.jikesrvm.classloader.TypeReference; 034import org.jikesrvm.compilers.common.CodeArray; 035import org.jikesrvm.mm.mmtk.FinalizableProcessor; 036import org.jikesrvm.mm.mmtk.ReferenceProcessor; 037import org.jikesrvm.mm.mmtk.SynchronizedCounter; 038import org.jikesrvm.objectmodel.BootImageInterface; 039import org.jikesrvm.objectmodel.IMT; 040import org.jikesrvm.objectmodel.ITable; 041import org.jikesrvm.objectmodel.ITableArray; 042import org.jikesrvm.objectmodel.JavaHeader; 043import org.jikesrvm.objectmodel.ObjectModel; 044import org.jikesrvm.objectmodel.TIB; 045import org.jikesrvm.options.OptionSet; 046import org.jikesrvm.runtime.BootRecord; 047import org.jikesrvm.runtime.Callbacks; 048import org.jikesrvm.runtime.Magic; 049import org.mmtk.plan.CollectorContext; 050import org.mmtk.plan.Plan; 051import org.mmtk.policy.Space; 052import org.mmtk.utility.Memory; 053import org.mmtk.utility.alloc.Allocator; 054import org.mmtk.utility.gcspy.GCspy; 055import org.mmtk.utility.heap.HeapGrowthManager; 056import org.mmtk.utility.heap.Mmapper; 057import org.mmtk.utility.options.Options; 058import org.vmmagic.pragma.Entrypoint; 059import org.vmmagic.pragma.Inline; 060import org.vmmagic.pragma.Interruptible; 061import org.vmmagic.pragma.NoInline; 062import org.vmmagic.pragma.Pure; 063import org.vmmagic.pragma.Uninterruptible; 064import org.vmmagic.pragma.Unpreemptible; 065import org.vmmagic.pragma.UnpreemptibleNoWarn; 066import org.vmmagic.unboxed.Address; 067import org.vmmagic.unboxed.Extent; 068import org.vmmagic.unboxed.ObjectReference; 069import org.vmmagic.unboxed.Offset; 070import org.vmmagic.unboxed.Word; 071import org.vmmagic.unboxed.WordArray; 072 073/** 074 * The interface that the MMTk memory manager presents to Jikes RVM 075 */ 076@Uninterruptible 077public final class MemoryManager { 078 079 /*********************************************************************** 080 * 081 * Class variables 082 */ 083 084 /** 085 * <code>true</code> if checking of allocated memory to ensure it is 086 * zeroed is desired. 087 */ 088 private static final boolean CHECK_MEMORY_IS_ZEROED = false; 089 private static final boolean traceAllocator = false; 090 091 /** 092 * Has the interface been booted yet? 093 */ 094 private static boolean booted = false; 095 096 /** 097 * Has garbage collection been enabled yet? 098 */ 099 private static boolean collectionEnabled = false; 100 101 /*********************************************************************** 102 * 103 * Initialization 104 */ 105 106 /** 107 * Suppress default constructor to enforce noninstantiability. 108 */ 109 private MemoryManager() {} // This constructor will never be invoked. 110 111 /** 112 * Initialization that occurs at <i>boot</i> time (runtime 113 * initialization). This is only executed by one processor (the 114 * primordial thread). 115 * @param theBootRecord the boot record. Contains information about 116 * the heap size. 117 */ 118 @Interruptible 119 public static void boot(BootRecord theBootRecord) { 120 Extent pageSize = BootRecord.the_boot_record.bytesInPage; 121 org.jikesrvm.runtime.Memory.setPageSize(pageSize); 122 Mmapper.markAsMapped(BOOT_IMAGE_DATA_START, BOOT_IMAGE_DATA_SIZE); 123 Mmapper.markAsMapped(BOOT_IMAGE_CODE_START, BOOT_IMAGE_CODE_SIZE); 124 HeapGrowthManager.boot(theBootRecord.initialHeapSize, theBootRecord.maximumHeapSize); 125 DebugUtil.boot(theBootRecord); 126 Selected.Plan.get().enableAllocation(); 127 SynchronizedCounter.boot(); 128 129 Callbacks.addExitMonitor(new Callbacks.ExitMonitor() { 130 @Override 131 public void notifyExit(int value) { 132 Selected.Plan.get().notifyExit(value); 133 } 134 }); 135 136 booted = true; 137 } 138 139 /** 140 * Perform postBoot operations such as dealing with command line 141 * options (this is called as soon as options have been parsed, 142 * which is necessarily after the basic allocator boot). 143 */ 144 @Interruptible 145 public static void postBoot() { 146 Selected.Plan.get().processOptions(); 147 148 if (Options.noReferenceTypes.getValue()) { 149 RVMType.JavaLangRefReferenceReferenceField.makeTraced(); 150 } 151 152 if (VM.BuildWithGCSpy) { 153 // start the GCSpy interpreter server 154 MemoryManager.startGCspyServer(); 155 } 156 } 157 158 /** 159 * Allow collection (assumes threads can be created). 160 */ 161 @Interruptible 162 public static void enableCollection() { 163 Selected.Plan.get().enableCollection(); 164 collectionEnabled = true; 165 } 166 167 /** 168 * @return whether collection is enabled 169 */ 170 public static boolean collectionEnabled() { 171 return collectionEnabled; 172 } 173 174 /** 175 * Notify the MM that the host VM is now fully booted. 176 */ 177 @Interruptible 178 public static void fullyBootedVM() { 179 Selected.Plan.get().fullyBooted(); 180 } 181 182 @Interruptible 183 public static void processCommandLineArg(String arg) { 184 if (!OptionSet.gc.process(arg)) { 185 VM.sysWriteln("Unrecognized command line argument: \"" + arg + "\""); 186 VM.sysExit(EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); 187 } 188 } 189 190 /*********************************************************************** 191 * 192 * Write barriers 193 */ 194 195 /** 196 * Checks that if a garbage collection is in progress then the given 197 * object is not movable. If it is movable error messages are 198 * logged and the system exits. 199 * 200 * @param object the object to check 201 */ 202 @Entrypoint 203 public static void modifyCheck(Object object) { 204 /* Make sure that during GC, we don't update on a possibly moving object. 205 Such updates are dangerous because they can be lost. 206 */ 207 if (Plan.gcInProgressProper()) { 208 ObjectReference ref = ObjectReference.fromObject(object); 209 if (Space.isMovable(ref)) { 210 VM.sysWriteln("GC modifying a potentially moving object via Java (i.e. not magic)"); 211 VM.sysWriteln(" obj = ", ref); 212 RVMType t = Magic.getObjectType(object); 213 VM.sysWrite(" type = "); 214 VM.sysWriteln(t.getDescriptor()); 215 VM.sysFail("GC modifying a potentially moving object via Java (i.e. not magic)"); 216 } 217 } 218 } 219 220 /*********************************************************************** 221 * 222 * Statistics 223 */ 224 225 /*********************************************************************** 226 * 227 * Application interface to memory manager 228 */ 229 230 /** 231 * Returns the amount of free memory. 232 * 233 * @return The amount of free memory. 234 */ 235 public static Extent freeMemory() { 236 return Plan.freeMemory(); 237 } 238 239 /** 240 * Returns the amount of total memory. 241 * 242 * @return The amount of total memory. 243 */ 244 public static Extent totalMemory() { 245 return Plan.totalMemory(); 246 } 247 248 /** 249 * Returns the maximum amount of memory VM will attempt to use. 250 * 251 * @return The maximum amount of memory VM will attempt to use. 252 */ 253 public static Extent maxMemory() { 254 return HeapGrowthManager.getMaxHeapSize(); 255 } 256 257 /** 258 * External call to force a garbage collection. 259 */ 260 @Interruptible 261 public static void gc() { 262 Selected.Plan.handleUserCollectionRequest(); 263 } 264 265 /**************************************************************************** 266 * 267 * Check references, log information about references 268 */ 269 270 /** 271 * Logs information about a reference to the error output. 272 * 273 * @param ref the address to log information about 274 */ 275 public static void dumpRef(ObjectReference ref) { 276 DebugUtil.dumpRef(ref); 277 } 278 279 /** 280 * Checks if a reference is valid. 281 * 282 * @param ref the address to be checked 283 * @return <code>true</code> if the reference is valid 284 */ 285 @Inline 286 public static boolean validRef(ObjectReference ref) { 287 if (booted) { 288 return DebugUtil.validRef(ref); 289 } else { 290 return true; 291 } 292 } 293 294 /** 295 * Checks if an address refers to an in-use area of memory. 296 * 297 * @param address the address to be checked 298 * @return <code>true</code> if the address refers to an in use area 299 */ 300 @Inline 301 public static boolean addressInVM(Address address) { 302 return Space.isMappedAddress(address); 303 } 304 305 /** 306 * Checks if a reference refers to an object in an in-use area of 307 * memory. 308 * 309 * <p>References may be addresses just outside the memory region 310 * allocated to the object. 311 * 312 * @param object the reference to be checked 313 * @return <code>true</code> if the object refered to is in an 314 * in-use area 315 */ 316 @Inline 317 public static boolean objectInVM(ObjectReference object) { 318 return Space.isMappedObject(object); 319 } 320 321 /** 322 * Return true if address is in a space which may contain stacks 323 * 324 * @param address The address to be checked 325 * @return true if the address is within a space which may contain stacks 326 */ 327 public static boolean mightBeFP(Address address) { 328 // In general we don't know which spaces may hold allocated stacks. 329 // If we want to be more specific than the space being mapped we 330 // will need to add a check in Plan that can be overriden. 331 return Space.isMappedAddress(address); 332 } 333 /*********************************************************************** 334 * 335 * Allocation 336 */ 337 338 /** 339 * Return an allocation site upon request. The request may be made 340 * in the context of compilation. 341 * 342 * @param compileTime {@code true} if this request is being made in the 343 * context of a compilation. 344 * @return an allocation site 345 */ 346 public static int getAllocationSite(boolean compileTime) { 347 return Plan.getAllocationSite(compileTime); 348 } 349 350 /** 351 * Returns the appropriate allocation scheme/area for the given 352 * type. This form is deprecated. Without the RVMMethod argument, 353 * it is possible that the wrong allocator is chosen which may 354 * affect correctness. The prototypical example is that JMTk 355 * meta-data must generally be in immortal or at least non-moving 356 * space. 357 * 358 * 359 * @param type the type of the object to be allocated 360 * @return the identifier of the appropriate allocator 361 */ 362 @Interruptible 363 public static int pickAllocator(RVMType type) { 364 return pickAllocator(type, null); 365 } 366 367 /** 368 * Is string <code>a</code> a prefix of string 369 * <code>b</code>. String <code>b</code> is encoded as an ASCII byte 370 * array. 371 * 372 * @param a prefix string 373 * @param b string which may contain prefix, encoded as an ASCII 374 * byte array. 375 * @return <code>true</code> if <code>a</code> is a prefix of 376 * <code>b</code> 377 */ 378 @Interruptible 379 private static boolean isPrefix(String a, byte[] b) { 380 int aLen = a.length(); 381 if (aLen > b.length) { 382 return false; 383 } 384 for (int i = 0; i < aLen; i++) { 385 if (a.charAt(i) != ((char) b[i])) { 386 return false; 387 } 388 } 389 return true; 390 } 391 392 /** 393 * Returns the appropriate allocation scheme/area for the given type 394 * and given method requesting the allocation. 395 * 396 * @param type the type of the object to be allocated 397 * @param method the method requesting the allocation 398 * @return the identifier of the appropriate allocator 399 */ 400 @Interruptible 401 public static int pickAllocator(RVMType type, RVMMethod method) { 402 if (traceAllocator) { 403 VM.sysWrite("allocator for "); 404 VM.sysWrite(type.getDescriptor()); 405 VM.sysWrite(": "); 406 } 407 if (method != null) { 408 // We should strive to be allocation-free here. 409 RVMClass cls = method.getDeclaringClass(); 410 byte[] clsBA = cls.getDescriptor().toByteArray(); 411 if (Selected.Constraints.get().withGCspy()) { 412 if (isPrefix("Lorg/mmtk/vm/gcspy/", clsBA) || isPrefix("[Lorg/mmtk/vm/gcspy/", clsBA)) { 413 if (traceAllocator) { 414 VM.sysWriteln("GCSPY"); 415 } 416 return Plan.ALLOC_GCSPY; 417 } 418 } 419 if (isPrefix("Lorg/jikesrvm/mm/mmtk/ReferenceProcessor", clsBA)) { 420 if (traceAllocator) { 421 VM.sysWriteln("DEFAULT"); 422 } 423 return Plan.ALLOC_DEFAULT; 424 } 425 if (isPrefix("Lorg/mmtk/", clsBA) || isPrefix("Lorg/jikesrvm/mm/", clsBA)) { 426 if (traceAllocator) { 427 VM.sysWriteln("NONMOVING"); 428 } 429 return Plan.ALLOC_NON_MOVING; 430 } 431 if (method.isNonMovingAllocation()) { 432 return Plan.ALLOC_NON_MOVING; 433 } 434 } 435 if (traceAllocator) { 436 VM.sysWriteln(type.getMMAllocator()); 437 } 438 return type.getMMAllocator(); 439 } 440 441 /** 442 * Determine the default allocator to be used for a given type. 443 * 444 * @param type The type in question 445 * @return The allocator to use for allocating instances of type 446 * <code>type</code>. 447 */ 448 @Interruptible 449 private static int pickAllocatorForType(RVMType type) { 450 int allocator = Plan.ALLOC_DEFAULT; 451 if (type.isArrayType()) { 452 RVMType elementType = type.asArray().getElementType(); 453 if (elementType.isPrimitiveType() || elementType.isUnboxedType()) { 454 allocator = Plan.ALLOC_NON_REFERENCE; 455 } 456 } 457 if (type.isNonMoving()) { 458 allocator = Plan.ALLOC_NON_MOVING; 459 } 460 byte[] typeBA = type.getDescriptor().toByteArray(); 461 if (Selected.Constraints.get().withGCspy()) { 462 if (isPrefix("Lorg/mmtk/vm/gcspy/", typeBA) || isPrefix("[Lorg/mmtk/vm/gcspy/", typeBA)) { 463 allocator = Plan.ALLOC_GCSPY; 464 } 465 } 466 if (isPrefix("Lorg/jikesrvm/tuningfork", typeBA) || isPrefix("[Lorg/jikesrvm/tuningfork", typeBA) || 467 isPrefix("Lcom/ibm/tuningfork/", typeBA) || isPrefix("[Lcom/ibm/tuningfork/", typeBA) || 468 isPrefix("Lorg/mmtk/", typeBA) || isPrefix("[Lorg/mmtk/", typeBA) || 469 isPrefix("Lorg/jikesrvm/mm/", typeBA) || isPrefix("[Lorg/jikesrvm/mm/", typeBA) || 470 isPrefix("Lorg/jikesrvm/jni/JNIEnvironment;", typeBA)) { 471 allocator = Plan.ALLOC_NON_MOVING; 472 } 473 return allocator; 474 } 475 476 /*********************************************************************** 477 * These methods allocate memory. Specialized versions are available for 478 * particular object types. 479 *********************************************************************** 480 */ 481 482 /** 483 * Allocate a scalar object. 484 * 485 * @param size Size in bytes of the object, including any headers 486 * that need space. 487 * @param tib Type of the object (pointer to TIB). 488 * @param allocator Specify which allocation scheme/area JMTk should 489 * allocate the memory from. 490 * @param align the alignment requested; must be a power of 2. 491 * @param offset the offset at which the alignment is desired. 492 * @param site allocation site. 493 * @return the initialized Object 494 */ 495 @Inline 496 public static Object allocateScalar(int size, TIB tib, int allocator, int align, int offset, int site) { 497 Selected.Mutator mutator = Selected.Mutator.get(); 498 allocator = mutator.checkAllocator(org.jikesrvm.runtime.Memory.alignUp(size, MIN_ALIGNMENT), align, allocator); 499 Address region = allocateSpace(mutator, size, align, offset, allocator, site); 500 Object result = ObjectModel.initializeScalar(region, tib, size); 501 mutator.postAlloc(ObjectReference.fromObject(result), ObjectReference.fromObject(tib), size, allocator); 502 return result; 503 } 504 505 /** 506 * Allocate an array object. This is the interruptible component, including throwing 507 * an OutOfMemoryError for arrays that are too large. 508 * 509 * @param numElements number of array elements 510 * @param logElementSize size in bytes of an array element, log base 2. 511 * @param headerSize size in bytes of array header 512 * @param tib type information block for array object 513 * @param allocator int that encodes which allocator should be used 514 * @param align the alignment requested; must be a power of 2. 515 * @param offset the offset at which the alignment is desired. 516 * @param site allocation site. 517 * @return array object with header installed and all elements set 518 * to zero/null 519 * See also: bytecode 0xbc ("newarray") and 0xbd ("anewarray") 520 */ 521 @Inline 522 @Unpreemptible 523 public static Object allocateArray(int numElements, int logElementSize, int headerSize, TIB tib, int allocator, 524 int align, int offset, int site) { 525 int elemBytes = numElements << logElementSize; 526 if ((elemBytes >>> logElementSize) != numElements) { 527 /* asked to allocate more than Integer.MAX_VALUE bytes */ 528 throwLargeArrayOutOfMemoryError(); 529 } 530 int size = elemBytes + headerSize; 531 return allocateArrayInternal(numElements, size, tib, allocator, align, offset, site); 532 } 533 534 535 /** 536 * Throw an out of memory error due to an array allocation request that is 537 * larger than the maximum allowed value. This is in a separate method 538 * so it can be forced out of line. 539 */ 540 @NoInline 541 @UnpreemptibleNoWarn 542 private static void throwLargeArrayOutOfMemoryError() { 543 throw new OutOfMemoryError(); 544 } 545 546 /** 547 * Allocate an array object. 548 * 549 * @param numElements The number of element bytes 550 * @param size size in bytes of array header 551 * @param tib type information block for array object 552 * @param allocator int that encodes which allocator should be used 553 * @param align the alignment requested; must be a power of 2. 554 * @param offset the offset at which the alignment is desired. 555 * @param site allocation site. 556 * @return array object with header installed and all elements set 557 * to zero/{@code null} 558 * See also: bytecode 0xbc ("newarray") and 0xbd ("anewarray") 559 */ 560 @Inline 561 private static Object allocateArrayInternal(int numElements, int size, TIB tib, int allocator, 562 int align, int offset, int site) { 563 Selected.Mutator mutator = Selected.Mutator.get(); 564 allocator = mutator.checkAllocator(org.jikesrvm.runtime.Memory.alignUp(size, MIN_ALIGNMENT), align, allocator); 565 Address region = allocateSpace(mutator, size, align, offset, allocator, site); 566 Object result = ObjectModel.initializeArray(region, tib, numElements, size); 567 mutator.postAlloc(ObjectReference.fromObject(result), ObjectReference.fromObject(tib), size, allocator); 568 return result; 569 } 570 571 /** 572 * Allocate space for runtime allocation of an object 573 * 574 * @param mutator The mutator instance to be used for this allocation 575 * @param bytes The size of the allocation in bytes 576 * @param align The alignment requested; must be a power of 2. 577 * @param offset The offset at which the alignment is desired. 578 * @param allocator The MMTk allocator to be used (if allocating) 579 * @param site Allocation site. 580 * @return The first byte of a suitably sized and aligned region of memory. 581 */ 582 @Inline 583 private static Address allocateSpace(Selected.Mutator mutator, int bytes, int align, int offset, int allocator, 584 int site) { 585 /* MMTk requests must be in multiples of MIN_ALIGNMENT */ 586 bytes = org.jikesrvm.runtime.Memory.alignUp(bytes, MIN_ALIGNMENT); 587 588 /* Now make the request */ 589 Address region; 590 region = mutator.alloc(bytes, align, offset, allocator, site); 591 592 /* TODO: if (Stats.GATHER_MARK_CONS_STATS) Plan.cons.inc(bytes); */ 593 if (CHECK_MEMORY_IS_ZEROED) Memory.assertIsZeroed(region, bytes); 594 595 return region; 596 } 597 598 /** 599 * Allocate space for GC-time copying of an object 600 * 601 * @param context The collector context to be used for this allocation 602 * @param bytes The size of the allocation in bytes 603 * @param allocator the allocator associated with this request 604 * @param align The alignment requested; must be a power of 2. 605 * @param offset The offset at which the alignment is desired. 606 * @param from The source object from which this is to be copied 607 * @return The first byte of a suitably sized and aligned region of memory. 608 */ 609 @Inline 610 public static Address allocateSpace(CollectorContext context, int bytes, int align, int offset, int allocator, 611 ObjectReference from) { 612 /* MMTk requests must be in multiples of MIN_ALIGNMENT */ 613 bytes = org.jikesrvm.runtime.Memory.alignUp(bytes, MIN_ALIGNMENT); 614 615 /* Now make the request */ 616 Address region; 617 region = context.allocCopy(from, bytes, align, offset, allocator); 618 619 /* TODO: if (Stats.GATHER_MARK_CONS_STATS) Plan.mark.inc(bytes); */ 620 if (CHECK_MEMORY_IS_ZEROED) Memory.assertIsZeroed(region, bytes); 621 622 return region; 623 } 624 625 /** 626 * Align an allocation using some modulo arithmetic to guarantee the 627 * following property:<br> 628 * <code>(region + offset) % alignment == 0</code> 629 * 630 * @param initialOffset The initial (unaligned) start value of the 631 * allocated region of memory. 632 * @param align The alignment requested, must be a power of two 633 * @param offset The offset at which the alignment is desired 634 * @return <code>initialOffset</code> plus some delta (possibly 0) such 635 * that the return value is aligned according to the above 636 * constraints. 637 */ 638 @Inline 639 public static Offset alignAllocation(Offset initialOffset, int align, int offset) { 640 Address region = org.jikesrvm.runtime.Memory.alignUp(initialOffset.toWord().toAddress(), MIN_ALIGNMENT); 641 return Allocator.alignAllocationNoFill(region, align, offset).toWord().toOffset(); 642 } 643 644 /** 645 * Allocate a CodeArray into a code space. 646 * Currently the interface is fairly primitive; 647 * just the number of instructions in the code array and a boolean 648 * to indicate hot or cold code. 649 * @param numInstrs number of instructions 650 * @param isHot is this a request for hot code space allocation? 651 * @return The array 652 */ 653 @NoInline 654 @Interruptible 655 public static CodeArray allocateCode(int numInstrs, boolean isHot) { 656 RVMArray type = RVMType.CodeArrayType; 657 int headerSize = ObjectModel.computeArrayHeaderSize(type); 658 int align = ObjectModel.getAlignment(type); 659 int offset = ObjectModel.getOffsetForAlignment(type, false); 660 int width = type.getLogElementSize(); 661 TIB tib = type.getTypeInformationBlock(); 662 int allocator = isHot ? Plan.ALLOC_HOT_CODE : Plan.ALLOC_COLD_CODE; 663 664 return (CodeArray) allocateArray(numInstrs, width, headerSize, tib, allocator, align, offset, Plan.DEFAULT_SITE); 665 } 666 667 /** 668 * Allocate a stack 669 * @param bytes The number of bytes to allocate 670 * @return The stack 671 */ 672 @NoInline 673 @Unpreemptible 674 public static byte[] newStack(int bytes) { 675 if (!VM.runningVM) { 676 return new byte[bytes]; 677 } else { 678 RVMArray stackType = RVMArray.ByteArray; 679 int headerSize = ObjectModel.computeArrayHeaderSize(stackType); 680 int align = ObjectModel.getAlignment(stackType); 681 int offset = ObjectModel.getOffsetForAlignment(stackType, false); 682 int width = stackType.getLogElementSize(); 683 TIB stackTib = stackType.getTypeInformationBlock(); 684 685 return (byte[]) allocateArray(bytes, 686 width, 687 headerSize, 688 stackTib, 689 Plan.ALLOC_STACK, 690 align, 691 offset, 692 Plan.DEFAULT_SITE); 693 } 694 } 695 696 /** 697 * Allocates a non moving word array. 698 * 699 * @param size The size of the array 700 * @return the new non moving word array 701 */ 702 @NoInline 703 @Interruptible 704 public static WordArray newNonMovingWordArray(int size) { 705 if (!VM.runningVM) { 706 return WordArray.create(size); 707 } 708 709 RVMArray arrayType = RVMType.WordArrayType; 710 int headerSize = ObjectModel.computeArrayHeaderSize(arrayType); 711 int align = ObjectModel.getAlignment(arrayType); 712 int offset = ObjectModel.getOffsetForAlignment(arrayType, false); 713 int width = arrayType.getLogElementSize(); 714 TIB arrayTib = arrayType.getTypeInformationBlock(); 715 716 return (WordArray) allocateArray(size, 717 width, 718 headerSize, 719 arrayTib, 720 Plan.ALLOC_NON_MOVING, 721 align, 722 offset, 723 Plan.DEFAULT_SITE); 724 725 } 726 727 /** 728 * Allocates a non moving double array. 729 * 730 * @param size The size of the array 731 * @return the new non moving double array 732 */ 733 @NoInline 734 @Interruptible 735 public static double[] newNonMovingDoubleArray(int size) { 736 if (!VM.runningVM) { 737 return new double[size]; 738 } 739 740 RVMArray arrayType = RVMArray.DoubleArray; 741 int headerSize = ObjectModel.computeArrayHeaderSize(arrayType); 742 int align = ObjectModel.getAlignment(arrayType); 743 int offset = ObjectModel.getOffsetForAlignment(arrayType, false); 744 int width = arrayType.getLogElementSize(); 745 TIB arrayTib = arrayType.getTypeInformationBlock(); 746 747 return (double[]) allocateArray(size, 748 width, 749 headerSize, 750 arrayTib, 751 Plan.ALLOC_NON_MOVING, 752 align, 753 offset, 754 Plan.DEFAULT_SITE); 755 756 } 757 758 /** 759 * Allocates a non moving int array. 760 * 761 * @param size The size of the array 762 * @return the new non moving int array 763 */ 764 @NoInline 765 @Interruptible 766 public static int[] newNonMovingIntArray(int size) { 767 if (!VM.runningVM) { 768 return new int[size]; 769 } 770 771 RVMArray arrayType = RVMArray.IntArray; 772 int headerSize = ObjectModel.computeArrayHeaderSize(arrayType); 773 int align = ObjectModel.getAlignment(arrayType); 774 int offset = ObjectModel.getOffsetForAlignment(arrayType, false); 775 int width = arrayType.getLogElementSize(); 776 TIB arrayTib = arrayType.getTypeInformationBlock(); 777 778 return (int[]) allocateArray(size, 779 width, 780 headerSize, 781 arrayTib, 782 Plan.ALLOC_NON_MOVING, 783 align, 784 offset, 785 Plan.DEFAULT_SITE); 786 787 } 788 789 /** 790 * Allocates a non moving short array. 791 * 792 * @param size The size of the array 793 * @return the new non moving short array 794 */ 795 @NoInline 796 @Interruptible 797 public static short[] newNonMovingShortArray(int size) { 798 if (!VM.runningVM) { 799 return new short[size]; 800 } 801 802 RVMArray arrayType = RVMArray.ShortArray; 803 int headerSize = ObjectModel.computeArrayHeaderSize(arrayType); 804 int align = ObjectModel.getAlignment(arrayType); 805 int offset = ObjectModel.getOffsetForAlignment(arrayType, false); 806 int width = arrayType.getLogElementSize(); 807 TIB arrayTib = arrayType.getTypeInformationBlock(); 808 809 return (short[]) allocateArray(size, 810 width, 811 headerSize, 812 arrayTib, 813 Plan.ALLOC_NON_MOVING, 814 align, 815 offset, 816 Plan.DEFAULT_SITE); 817 818 } 819 820 /** 821 * Allocates a new type information block (TIB). 822 * 823 * @param numVirtualMethods the number of virtual method slots in the TIB 824 * @param alignCode alignment encoding for the TIB 825 * @return the new TIB 826 * @see AlignmentEncoding 827 */ 828 @NoInline 829 @Interruptible 830 public static TIB newTIB(int numVirtualMethods, int alignCode) { 831 int elements = TIB.computeSize(numVirtualMethods); 832 833 if (!VM.runningVM) { 834 return TIB.allocate(elements, alignCode); 835 } 836 if (alignCode == AlignmentEncoding.ALIGN_CODE_NONE) { 837 return (TIB)newRuntimeTable(elements, RVMType.TIBType); 838 } 839 840 RVMType type = RVMType.TIBType; 841 if (VM.VerifyAssertions) VM._assert(VM.runningVM); 842 843 TIB realTib = type.getTypeInformationBlock(); 844 RVMArray fakeType = RVMType.WordArrayType; 845 TIB fakeTib = fakeType.getTypeInformationBlock(); 846 int headerSize = ObjectModel.computeArrayHeaderSize(fakeType); 847 int align = ObjectModel.getAlignment(fakeType); 848 int offset = ObjectModel.getOffsetForAlignment(fakeType, false); 849 int width = fakeType.getLogElementSize(); 850 int elemBytes = elements << width; 851 if ((elemBytes >>> width) != elements) { 852 /* asked to allocate more than Integer.MAX_VALUE bytes */ 853 throwLargeArrayOutOfMemoryError(); 854 } 855 int size = elemBytes + headerSize + AlignmentEncoding.padding(alignCode); 856 Selected.Mutator mutator = Selected.Mutator.get(); 857 Address region = allocateSpace(mutator, size, align, offset, type.getMMAllocator(), Plan.DEFAULT_SITE); 858 859 region = AlignmentEncoding.adjustRegion(alignCode, region); 860 861 Object result = ObjectModel.initializeArray(region, fakeTib, elements, size); 862 mutator.postAlloc(ObjectReference.fromObject(result), ObjectReference.fromObject(fakeTib), size, type.getMMAllocator()); 863 864 /* Now we replace the TIB */ 865 ObjectModel.setTIB(result, realTib); 866 867 return (TIB)result; 868 } 869 870 /** 871 * Allocate a new interface method table (IMT). 872 * 873 * @return the new IMT 874 */ 875 @NoInline 876 @Interruptible 877 public static IMT newIMT() { 878 if (!VM.runningVM) { 879 return IMT.allocate(); 880 } 881 882 return (IMT)newRuntimeTable(IMT_METHOD_SLOTS, RVMType.IMTType); 883 } 884 885 /** 886 * Allocate a new ITable 887 * 888 * @param size the number of slots in the ITable 889 * @return the new ITable 890 */ 891 @NoInline 892 @Interruptible 893 public static ITable newITable(int size) { 894 if (!VM.runningVM) { 895 return ITable.allocate(size); 896 } 897 898 return (ITable)newRuntimeTable(size, RVMType.ITableType); 899 } 900 901 /** 902 * Allocate a new ITableArray 903 * 904 * @param size the number of slots in the ITableArray 905 * @return the new ITableArray 906 */ 907 @NoInline 908 @Interruptible 909 public static ITableArray newITableArray(int size) { 910 if (!VM.runningVM) { 911 return ITableArray.allocate(size); 912 } 913 914 return (ITableArray)newRuntimeTable(size, RVMType.ITableArrayType); 915 } 916 917 /** 918 * Allocates a new runtime table (at runtime). 919 * 920 * @param size The size of the table 921 * @param type the type for the table 922 * @return the newly allocated table 923 */ 924 @NoInline 925 @Interruptible 926 public static Object newRuntimeTable(int size, RVMType type) { 927 if (VM.VerifyAssertions) VM._assert(VM.runningVM); 928 929 TIB realTib = type.getTypeInformationBlock(); 930 RVMArray fakeType = RVMType.WordArrayType; 931 TIB fakeTib = fakeType.getTypeInformationBlock(); 932 int headerSize = ObjectModel.computeArrayHeaderSize(fakeType); 933 int align = ObjectModel.getAlignment(fakeType); 934 int offset = ObjectModel.getOffsetForAlignment(fakeType, false); 935 int width = fakeType.getLogElementSize(); 936 937 /* Allocate a word array */ 938 Object array = allocateArray(size, 939 width, 940 headerSize, 941 fakeTib, 942 type.getMMAllocator(), 943 align, 944 offset, 945 Plan.DEFAULT_SITE); 946 947 /* Now we replace the TIB */ 948 ObjectModel.setTIB(array, realTib); 949 return array; 950 } 951 952 /** 953 * Checks if the object can move. This information is useful to 954 * optimize some JNI calls. 955 * 956 * @param obj the object in question 957 * @return {@code true} if this object can never move, {@code false} 958 * if it can move. 959 */ 960 @Pure 961 public static boolean willNeverMove(Object obj) { 962 return Selected.Plan.get().willNeverMove(ObjectReference.fromObject(obj)); 963 } 964 965 /** 966 * @param obj the object in question 967 * @return whether the object is immortal 968 */ 969 @Pure 970 public static boolean isImmortal(Object obj) { 971 return Space.isImmortal(ObjectReference.fromObject(obj)); 972 } 973 974 /*********************************************************************** 975 * 976 * Finalizers 977 */ 978 979 /** 980 * Adds an object to the list of objects to have their 981 * <code>finalize</code> method called when they are reclaimed. 982 * 983 * @param object the object to be added to the finalizer's list 984 */ 985 @Interruptible 986 public static void addFinalizer(Object object) { 987 FinalizableProcessor.addCandidate(object); 988 } 989 990 /** 991 * Gets an object from the list of objects that are to be reclaimed 992 * and need to have their <code>finalize</code> method called. 993 * 994 * @return the object needing to be finialized 995 */ 996 @Unpreemptible("Non-preemptible but may yield if finalizable table is being grown") 997 public static Object getFinalizedObject() { 998 return FinalizableProcessor.getForFinalize(); 999 } 1000 1001 /*********************************************************************** 1002 * 1003 * References 1004 */ 1005 1006 /** 1007 * Add a soft reference to the list of soft references. 1008 * 1009 * @param obj the soft reference to be added to the list 1010 * @param referent the object that the reference points to 1011 */ 1012 @Interruptible 1013 public static void addSoftReference(SoftReference<?> obj, Object referent) { 1014 ReferenceProcessor.addSoftCandidate(obj,ObjectReference.fromObject(referent)); 1015 } 1016 1017 /** 1018 * Add a weak reference to the list of weak references. 1019 * 1020 * @param obj the weak reference to be added to the list 1021 * @param referent the object that the reference points to 1022 */ 1023 @Interruptible 1024 public static void addWeakReference(WeakReference<?> obj, Object referent) { 1025 ReferenceProcessor.addWeakCandidate(obj,ObjectReference.fromObject(referent)); 1026 } 1027 1028 /** 1029 * Add a phantom reference to the list of phantom references. 1030 * 1031 * @param obj the phantom reference to be added to the list 1032 * @param referent the object that the reference points to 1033 */ 1034 @Interruptible 1035 public static void addPhantomReference(PhantomReference<?> obj, Object referent) { 1036 ReferenceProcessor.addPhantomCandidate(obj,ObjectReference.fromObject(referent)); 1037 } 1038 1039 /*********************************************************************** 1040 * 1041 * Tracing 1042 */ 1043 1044 /*********************************************************************** 1045 * 1046 * Heap size and heap growth 1047 */ 1048 1049 /** 1050 * Return the max heap size in bytes (as set by -Xmx). 1051 * 1052 * @return The max heap size in bytes (as set by -Xmx). 1053 */ 1054 public static Extent getMaxHeapSize() { 1055 return HeapGrowthManager.getMaxHeapSize(); 1056 } 1057 1058 /*********************************************************************** 1059 * 1060 * Miscellaneous 1061 */ 1062 1063 /** 1064 * A new type has been resolved by the VM. Create a new MM type to 1065 * reflect the VM type, and associate the MM type with the VM type. 1066 * 1067 * @param vmType The newly resolved type 1068 */ 1069 @Interruptible 1070 public static void notifyClassResolved(RVMType vmType) { 1071 vmType.setMMAllocator(pickAllocatorForType(vmType)); 1072 } 1073 1074 /** 1075 * Check if object might be a TIB. 1076 * 1077 * @param obj address of object to check 1078 * @return <code>false</code> if the object is in the wrong 1079 * allocation scheme/area for a TIB, <code>true</code> otherwise 1080 */ 1081 @Inline 1082 public static boolean mightBeTIB(ObjectReference obj) { 1083 return !obj.isNull() && 1084 Space.isMappedObject(obj) && 1085 Space.isMappedObject(ObjectReference.fromObject(ObjectModel.getTIB(obj))); 1086 } 1087 1088 /** 1089 * Returns true if GC is in progress. 1090 * 1091 * @return True if GC is in progress. 1092 */ 1093 public static boolean gcInProgress() { 1094 return Plan.gcInProgress(); 1095 } 1096 1097 /** 1098 * Start the GCspy server 1099 */ 1100 @Interruptible 1101 public static void startGCspyServer() { 1102 GCspy.startGCspyServer(); 1103 } 1104 1105 /** 1106 * Flush the mutator context. 1107 */ 1108 public static void flushMutatorContext() { 1109 Selected.Mutator.get().flush(); 1110 } 1111 1112 /** 1113 * @return the number of specialized methods. 1114 */ 1115 public static int numSpecializedMethods() { 1116 return SpecializedScanMethod.ENABLED ? Selected.Constraints.get().numSpecializedScans() : 0; 1117 } 1118 1119 /** 1120 * Initialize a specified specialized method. 1121 * 1122 * @param id the specializedMethod 1123 * @return the created specialized scan method 1124 */ 1125 @Interruptible 1126 public static SpecializedMethod createSpecializedMethod(int id) { 1127 if (VM.VerifyAssertions) { 1128 VM._assert(SpecializedScanMethod.ENABLED); 1129 VM._assert(id < Selected.Constraints.get().numSpecializedScans()); 1130 } 1131 1132 /* What does the plan want us to specialize this to? */ 1133 Class<?> traceClass = Selected.Plan.get().getSpecializedScanClass(id); 1134 1135 /* Create the specialized method */ 1136 return new SpecializedScanMethod(id, TypeReference.findOrCreate(traceClass)); 1137 } 1138 1139 /*********************************************************************** 1140 * 1141 * Header initialization 1142 */ 1143 1144 /** 1145 * Override the boot-time initialization method here, so that 1146 * the core MMTk code doesn't need to know about the 1147 * BootImageInterface type. 1148 * 1149 * @param bootImage the bootimage instance 1150 * @param ref the object's address 1151 * @param tib the object's TIB 1152 * @param size the number of bytes allocated by the GC system for 1153 * the object 1154 * @param isScalar whether the header belongs to a scalar or an array 1155 */ 1156 @Interruptible 1157 public static void initializeHeader(BootImageInterface bootImage, Address ref, TIB tib, int size, 1158 boolean isScalar) { 1159 // int status = JavaHeader.readAvailableBitsWord(bootImage, ref); 1160 byte status = Selected.Plan.get().setBuildTimeGCByte(ref, ObjectReference.fromObject(tib), size); 1161 JavaHeader.writeAvailableByte(bootImage, ref, status); 1162 } 1163 1164 /** 1165 * Installs a reference into the boot image. 1166 * 1167 * @param value the reference to install 1168 * @return the installed reference 1169 */ 1170 @Interruptible 1171 public static Word bootTimeWriteBarrier(Word value) { 1172 return Selected.Plan.get().bootTimeWriteBarrier(value); 1173 } 1174 1175 /*********************************************************************** 1176 * 1177 * Deprecated and/or broken. The following need to be expunged. 1178 */ 1179 1180 /** 1181 * Returns the maximum number of heaps that can be managed. 1182 * 1183 * @return the maximum number of heaps 1184 */ 1185 public static int getMaxHeaps() { 1186 /* 1187 * The boot record has a table of address ranges of the heaps, 1188 * the maximum number of heaps is used to size the table. 1189 */ 1190 return Space.MAX_SPACES; 1191 } 1192 1193 /** 1194 * Allocate a contiguous int array 1195 * @param n The number of ints 1196 * @return The contiguous int array 1197 */ 1198 @Inline 1199 @Interruptible 1200 public static int[] newContiguousIntArray(int n) { 1201 return new int[n]; 1202 } 1203 1204} 1205