hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapSet.java
author coleenp
Sun, 13 Apr 2008 17:43:42 -0400
changeset 360 21d113ecbf6a
parent 1 489c9b5090e2
child 670 ddf3e9583f2f
permissions -rw-r--r--
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes Summary: Compressed oops in instances, arrays, and headers. Code contributors are coleenp, phh, never, swamyv Reviewed-by: jmasa, kamg, acorn, tbell, kvn, rasbold

/*
 * Copyright 2000-2005 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 *
 */

package sun.jvm.hotspot.compiler;

import java.util.*;

import sun.jvm.hotspot.code.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.utilities.*;

public class OopMapSet extends VMObject {
  private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.compiler.OopMapSet.DEBUG") != null;

  private static CIntegerField omCountField;
  private static CIntegerField omSizeField;
  private static AddressField  omDataField;
  private static int REG_COUNT;
  private static int SAVED_ON_ENTRY_REG_COUNT;
  private static int C_SAVED_ON_ENTRY_REG_COUNT;
  private static class MyVisitor implements OopMapVisitor {
    private AddressVisitor addressVisitor;

    public MyVisitor(AddressVisitor oopVisitor) {
      setAddressVisitor(oopVisitor);
    }

    public void setAddressVisitor(AddressVisitor addressVisitor) {
      this.addressVisitor = addressVisitor;
    }

    public void visitOopLocation(Address oopAddr) {
      addressVisitor.visitAddress(oopAddr);
    }

    public void visitDerivedOopLocation(Address baseOopAddr, Address derivedOopAddr) {
      if (VM.getVM().isClientCompiler()) {
        Assert.that(false, "should not reach here");
      } else if (VM.getVM().isServerCompiler() &&
                 VM.getVM().useDerivedPointerTable()) {
        Assert.that(false, "FIXME: add derived pointer table");
      }
    }

    public void visitValueLocation(Address valueAddr) {
    }

    public void visitNarrowOopLocation(Address narrowOopAddr) {
      addressVisitor.visitCompOopAddress(narrowOopAddr);
    }
  }

  static {
    VM.registerVMInitializedObserver(new Observer() {
        public void update(Observable o, Object data) {
          initialize(VM.getVM().getTypeDataBase());
        }
      });
  }

  private static void initialize(TypeDataBase db) {
    Type type = db.lookupType("OopMapSet");

    omCountField  = type.getCIntegerField("_om_count");
    omSizeField   = type.getCIntegerField("_om_size");
    omDataField   = type.getAddressField("_om_data");

    if (!VM.getVM().isCore()) {
      REG_COUNT = db.lookupIntConstant("REG_COUNT").intValue();
      if (VM.getVM().isServerCompiler()) {
        SAVED_ON_ENTRY_REG_COUNT = (int) db.lookupIntConstant("SAVED_ON_ENTRY_REG_COUNT").intValue();
        C_SAVED_ON_ENTRY_REG_COUNT = (int) db.lookupIntConstant("C_SAVED_ON_ENTRY_REG_COUNT").intValue();
      }
    }
  }

  public OopMapSet(Address addr) {
    super(addr);
  }

  /** Returns the number of OopMaps in this OopMapSet */
  public long getSize() {
    return omCountField.getValue(addr);
  }

  /** returns the OopMap at a given index */
  public OopMap getMapAt(int index) {
    if (Assert.ASSERTS_ENABLED) {
      Assert.that((index >= 0) && (index <= getSize()),"bad index");
    }
    Address omDataAddr = omDataField.getValue(addr);
    Address oopMapAddr = omDataAddr.getAddressAt(index * VM.getVM().getAddressSize());
    if (oopMapAddr == null) {
      return null;
    }
    return new OopMap(oopMapAddr);
  }

  public OopMap findMapAtOffset(long pcOffset, boolean debugging) {
    int i;
    int len = (int) getSize();
    if (Assert.ASSERTS_ENABLED) {
      Assert.that(len > 0, "must have pointer maps");
    }

    // Scan through oopmaps. Stop when current offset is either equal or greater
    // than the one we are looking for.
    for (i = 0; i < len; i++) {
      if (getMapAt(i).getOffset() >= pcOffset) {
        break;
      }
    }

    if (!debugging) {
      if (Assert.ASSERTS_ENABLED) {
        Assert.that(i < len, "oopmap not found for pcOffset = " + pcOffset + "; len = " + len);
        Assert.that(getMapAt(i).getOffset() == pcOffset, "oopmap not found");
      }
    } else {
      if (i == len) {
        if (DEBUG) {
          System.out.println("can't find oopmap at " + pcOffset);
          System.out.print("Oopmap offsets are [ ");
          for (i = 0; i < len; i++) {
            System.out.print(getMapAt(i).getOffset());
          }
          System.out.println("]");
        }
        i = len - 1;
        return getMapAt(i);
      }
    }

    OopMap m = getMapAt(i);
    return m;
  }

  /** Visitation -- iterates through the frame for a compiled method.
      This is a very generic mechanism that requires the Address to be
      dereferenced by the callee. Other, more specialized, visitation
      mechanisms are given below. */
  public static void oopsDo(Frame fr, CodeBlob cb, RegisterMap regMap, AddressVisitor oopVisitor, boolean debugging) {
    allDo(fr, cb, regMap, new MyVisitor(oopVisitor), debugging);
  }

  /** Note that there are 4 required AddressVisitors: one for oops,
      one for derived oops, one for values, and one for dead values */
  public static void allDo(Frame fr, CodeBlob cb, RegisterMap regMap, OopMapVisitor visitor, boolean debugging) {
    if (Assert.ASSERTS_ENABLED) {
      CodeBlob tmpCB = VM.getVM().getCodeCache().findBlob(fr.getPC());
      Assert.that(tmpCB != null && cb.equals(tmpCB), "wrong codeblob passed in");
    }

    OopMapSet maps = cb.getOopMaps();
    OopMap map = cb.getOopMapForReturnAddress(fr.getPC(), debugging);
    if (Assert.ASSERTS_ENABLED) {
      Assert.that(map != null, "no ptr map found");
    }

    // handle derived pointers first (otherwise base pointer may be
    // changed before derived pointer offset has been collected)
    OopMapValue omv;
    {
      for (OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.DERIVED_OOP_VALUE); !oms.isDone(); oms.next()) {
        if (VM.getVM().isClientCompiler()) {
          Assert.that(false, "should not reach here");
        }
        omv = oms.getCurrent();
        Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap);
        if (loc != null) {
          Address baseLoc    = fr.oopMapRegToLocation(omv.getContentReg(), regMap);
          Address derivedLoc = loc;
          visitor.visitDerivedOopLocation(baseLoc, derivedLoc);
        }
      }
    }

    // We want narow oop, value and oop oop_types
    OopMapValue.OopTypes[] values = new OopMapValue.OopTypes[] {
      OopMapValue.OopTypes.OOP_VALUE, OopMapValue.OopTypes.VALUE_VALUE, OopMapValue.OopTypes.NARROWOOP_VALUE
    };

    {
      for (OopMapStream oms = new OopMapStream(map, values); !oms.isDone(); oms.next()) {
        omv = oms.getCurrent();
        Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap);
        if (loc != null) {
          if (omv.getType() == OopMapValue.OopTypes.OOP_VALUE) {
            // This assert commented out because this will be useful
            // to detect in the debugging system
            // assert(Universe::is_heap_or_null(*loc), "found non oop pointer");
            visitor.visitOopLocation(loc);
          } else if (omv.getType() == OopMapValue.OopTypes.VALUE_VALUE) {
            visitor.visitValueLocation(loc);
          } else if (omv.getType() == OopMapValue.OopTypes.NARROWOOP_VALUE) {
            visitor.visitNarrowOopLocation(loc);
          }
        }
      }
    }
  }

  /** Update callee-saved register info for the following frame.
      Should only be called in non-core builds. */
  public static void updateRegisterMap(Frame fr, CodeBlob cb, RegisterMap regMap, boolean debugging) {
    if (Assert.ASSERTS_ENABLED) {
      Assert.that(!VM.getVM().isCore(), "non-core builds only");
    }

    if (!VM.getVM().isDebugging()) {
      if (Assert.ASSERTS_ENABLED) {
        OopMapSet maps = cb.getOopMaps();
        Assert.that((maps != null) && (maps.getSize() > 0), "found null or empty OopMapSet for CodeBlob");
      }
    } else {
      // Hack for some topmost frames that have been found with empty
      // OopMapSets. (Actually have not seen the null case, but don't
      // want to take any chances.) See HSDB.showThreadStackMemory().
      OopMapSet maps = cb.getOopMaps();
      if ((maps == null) || (maps.getSize() == 0)) {
        return;
      }
    }

    // Check if caller must update oop argument
    regMap.setIncludeArgumentOops(cb.callerMustGCArguments(regMap.getThread()));

    int nofCallee = 0;
    Address[] locs = new Address[2 * REG_COUNT + 1];
    VMReg  [] regs = new VMReg  [2 * REG_COUNT + 1];
    // ("+1" because REG_COUNT might be zero)

    // Scan through oopmap and find location of all callee-saved registers
    // (we do not do update in place, since info could be overwritten)
    OopMap map  = cb.getOopMapForReturnAddress(fr.getPC(), debugging);
    if (Assert.ASSERTS_ENABLED) {
      Assert.that(map != null, "no ptr map found");
    }

    OopMapValue omv = null;
    for(OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE); !oms.isDone(); oms.next()) {
      omv = oms.getCurrent();
      if (Assert.ASSERTS_ENABLED) {
        Assert.that(nofCallee < 2 * REG_COUNT, "overflow");
      }
      regs[nofCallee] = omv.getContentReg();
      locs[nofCallee] = fr.oopMapRegToLocation(omv.getReg(), regMap);
      nofCallee++;
    }

    // Check that runtime stubs save all callee-saved registers
    // After adapter frames were deleted C2 doesn't use callee save registers at present
    if (Assert.ASSERTS_ENABLED) {
      if (VM.getVM().isServerCompiler()) {
        Assert.that(!cb.isRuntimeStub() ||
                    (nofCallee >= SAVED_ON_ENTRY_REG_COUNT || nofCallee >= C_SAVED_ON_ENTRY_REG_COUNT),
                    "must save all");
      }
    }

    // Copy found callee-saved register to reg_map
    for (int i = 0; i < nofCallee; i++) {
      regMap.setLocation(regs[i], locs[i]);
    }
  }
}