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.mmtk.policy.immix;
014    
015    import static org.mmtk.policy.immix.ImmixConstants.*;
016    
017    import org.mmtk.utility.Constants;
018    import org.mmtk.vm.VM;
019    
020    import org.vmmagic.pragma.Inline;
021    import org.vmmagic.pragma.Uninterruptible;
022    import org.vmmagic.unboxed.Address;
023    import org.vmmagic.unboxed.ObjectReference;
024    import org.vmmagic.unboxed.Offset;
025    
026    @Uninterruptible
027    public class Line implements Constants {
028    
029      public static Address align(Address ptr) {
030        return ptr.toWord().and(LINE_MASK.not()).toAddress();
031      }
032    
033      public static boolean isAligned(Address address) {
034        return address.EQ(align(address));
035      }
036    
037      static int getChunkIndex(Address line) {
038        return line.toWord().and(CHUNK_MASK).rshl(LOG_BYTES_IN_LINE).toInt();
039      }
040    
041     /***************************************************************************
042      * Line marking
043      */
044      static void mark(Address address, final byte markValue) {
045        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Block.isUnused(Block.align(address)));
046        getMarkAddress(address).store(markValue);
047      }
048    
049      static void markMultiLine(Address start, ObjectReference object, final byte markValue) {
050        /* endLine is the address of the last (highest) line touched by this object */
051        Address endLine = Line.align(VM.objectModel.getObjectEndAddress(object).minus(1));
052        Address line = Line.align(start.plus(BYTES_IN_LINE));
053        while (line.LT(endLine)) {
054          if (VM.VERIFY_ASSERTIONS)
055            VM.assertions._assert(Block.align(start).EQ(Block.align(line)));
056          mark(line, markValue);
057          line = line.plus(BYTES_IN_LINE);
058        }
059      }
060    
061      /***************************************************************************
062       * Scanning through avail lines
063       */
064      public static Address getChunkMarkTable(Address chunk) {
065        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Chunk.isAligned(chunk));
066        return getMarkAddress(chunk);
067      }
068    
069      public static Address getBlockMarkTable(Address block) {
070        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Block.isAligned(block));
071        return getMarkAddress(block);
072      }
073    
074      @Inline
075      public static int getNextUnavailable(Address baseLineAvailAddress, int line, final byte unavailableState) {
076        while (line < LINES_IN_BLOCK &&
077            baseLineAvailAddress.loadByte(Offset.fromIntZeroExtend(line<<Line.LOG_BYTES_IN_LINE_STATUS)) < unavailableState)
078          line++;
079        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(line >= 0 && line <= LINES_IN_BLOCK);
080        return line;
081      }
082    
083      @Inline
084      public static int getNextAvailable(Address baseLineAvailAddress, int line, final byte unavailableState) {
085        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(line >= 0 && line < LINES_IN_BLOCK);
086        byte last = baseLineAvailAddress.loadByte(Offset.fromIntZeroExtend(line<<Line.LOG_BYTES_IN_LINE_STATUS));
087        byte thisline;
088        line++;
089        while (line < LINES_IN_BLOCK) {
090          thisline = baseLineAvailAddress.loadByte(Offset.fromIntZeroExtend(line<<Line.LOG_BYTES_IN_LINE_STATUS));
091          if (thisline < unavailableState && last < unavailableState)
092            break;
093          last = thisline;
094          line++;
095        }
096        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(line >= 0 && line <= LINES_IN_BLOCK);
097        return line;
098      }
099    
100      private static Address getMetaAddress(Address address, final int tableOffset) {
101        Address chunk = Chunk.align(address);
102        int index = getChunkIndex(address);
103        Address rtn = chunk.plus(tableOffset + (index<<LOG_BYTES_IN_LINE_STATUS));
104        if (VM.VERIFY_ASSERTIONS) {
105          Address line = chunk.plus(index<<LOG_BYTES_IN_LINE);
106          VM.assertions._assert(isAligned(line));
107          VM.assertions._assert(align(address).EQ(line));
108          boolean valid = rtn.GE(chunk.plus(tableOffset)) && rtn.LT(chunk.plus(tableOffset + LINE_MARK_TABLE_BYTES));
109          VM.assertions._assert(valid);
110        }
111        return rtn;
112      }
113    
114      private static Address getMarkAddress(Address address) {
115        return getMetaAddress(address, Chunk.LINE_MARK_TABLE_OFFSET);
116      }
117    
118      /* per-line mark bytes */
119      static final int LOG_BYTES_IN_LINE_STATUS = 0;
120      static final int BYTES_IN_LINE_STATUS = 1<<LOG_BYTES_IN_LINE_STATUS;
121    
122      static final int LINE_MARK_TABLE_BYTES = LINES_IN_CHUNK<<LOG_BYTES_IN_LINE_STATUS;
123      static final int LOG_LINE_MARK_BYTES_PER_BLOCK = LOG_LINES_IN_BLOCK+LOG_BYTES_IN_LINE_STATUS;
124      static final int LINE_MARK_BYTES_PER_BLOCK = (1<<LOG_LINE_MARK_BYTES_PER_BLOCK);
125    }