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    
045      /**
046       *
047       */
048      static void mark(Address address, final byte markValue) {
049        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Block.isUnused(Block.align(address)));
050        getMarkAddress(address).store(markValue);
051      }
052    
053      static void markMultiLine(Address start, ObjectReference object, final byte markValue) {
054        /* endLine is the address of the last (highest) line touched by this object */
055        Address endLine = Line.align(VM.objectModel.getObjectEndAddress(object).minus(1));
056        Address line = Line.align(start.plus(BYTES_IN_LINE));
057        while (line.LT(endLine)) {
058          if (VM.VERIFY_ASSERTIONS)
059            VM.assertions._assert(Block.align(start).EQ(Block.align(line)));
060          mark(line, markValue);
061          line = line.plus(BYTES_IN_LINE);
062        }
063      }
064    
065      /***************************************************************************
066       * Scanning through avail lines
067       */
068    
069      /**
070       *
071       */
072      public static Address getChunkMarkTable(Address chunk) {
073        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Chunk.isAligned(chunk));
074        return getMarkAddress(chunk);
075      }
076    
077      public static Address getBlockMarkTable(Address block) {
078        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Block.isAligned(block));
079        return getMarkAddress(block);
080      }
081    
082      @Inline
083      public static int getNextUnavailable(Address baseLineAvailAddress, int line, final byte unavailableState) {
084        while (line < LINES_IN_BLOCK &&
085            baseLineAvailAddress.loadByte(Offset.fromIntZeroExtend(line<<Line.LOG_BYTES_IN_LINE_STATUS)) < unavailableState)
086          line++;
087        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(line >= 0 && line <= LINES_IN_BLOCK);
088        return line;
089      }
090    
091      @Inline
092      public static int getNextAvailable(Address baseLineAvailAddress, int line, final byte unavailableState) {
093        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(line >= 0 && line < LINES_IN_BLOCK);
094        byte last = baseLineAvailAddress.loadByte(Offset.fromIntZeroExtend(line<<Line.LOG_BYTES_IN_LINE_STATUS));
095        byte thisline;
096        line++;
097        while (line < LINES_IN_BLOCK) {
098          thisline = baseLineAvailAddress.loadByte(Offset.fromIntZeroExtend(line<<Line.LOG_BYTES_IN_LINE_STATUS));
099          if (thisline < unavailableState && last < unavailableState)
100            break;
101          last = thisline;
102          line++;
103        }
104        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(line >= 0 && line <= LINES_IN_BLOCK);
105        return line;
106      }
107    
108      private static Address getMetaAddress(Address address, final int tableOffset) {
109        Address chunk = Chunk.align(address);
110        int index = getChunkIndex(address);
111        Address rtn = chunk.plus(tableOffset + (index<<LOG_BYTES_IN_LINE_STATUS));
112        if (VM.VERIFY_ASSERTIONS) {
113          Address line = chunk.plus(index<<LOG_BYTES_IN_LINE);
114          VM.assertions._assert(isAligned(line));
115          VM.assertions._assert(align(address).EQ(line));
116          boolean valid = rtn.GE(chunk.plus(tableOffset)) && rtn.LT(chunk.plus(tableOffset + LINE_MARK_TABLE_BYTES));
117          VM.assertions._assert(valid);
118        }
119        return rtn;
120      }
121    
122      private static Address getMarkAddress(Address address) {
123        return getMetaAddress(address, Chunk.LINE_MARK_TABLE_OFFSET);
124      }
125    
126      /* per-line mark bytes */
127    
128      static final int LOG_BYTES_IN_LINE_STATUS = 0;
129      static final int BYTES_IN_LINE_STATUS = 1<<LOG_BYTES_IN_LINE_STATUS;
130    
131      static final int LINE_MARK_TABLE_BYTES = LINES_IN_CHUNK<<LOG_BYTES_IN_LINE_STATUS;
132      static final int LOG_LINE_MARK_BYTES_PER_BLOCK = LOG_LINES_IN_BLOCK+LOG_BYTES_IN_LINE_STATUS;
133      static final int LINE_MARK_BYTES_PER_BLOCK = (1<<LOG_LINE_MARK_BYTES_PER_BLOCK);
134    }