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