/* * Copyright (c) 2011, 2012, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.max.tele.method; import java.io.*; import java.util.*; import com.sun.max.program.*; import com.sun.max.tele.*; import com.sun.max.tele.object.*; import com.sun.max.tele.reference.*; import com.sun.max.tele.util.*; import com.sun.max.unsafe.*; import com.sun.max.vm.code.*; import com.sun.max.vm.compiler.target.*; /** * Access to the information in the code cache region that * is part of the boot image. * * @see CodeRegion * @see VmCodeCacheAccess * @see TargetMethod */ public final class VmBootCodeCacheRegion extends VmCodeCacheRegion { private static final int TRACE_VALUE = 1; private final TimedTrace updateTracer; private final String entityDescription; /** * The object in the VM that describes this code region. */ private final TeleCodeRegion teleCodeRegion; private final List<MaxObject> inspectableObjects; /** * Local manager of code regions. */ private final VmCodeCacheAccess codeCache; private final RemoteCodePointerManager codePointerManager; /** * Known method compilations in the region, organized for efficient lookup by address. * Map: Address --> TeleCompilation */ private final AddressToCompilationMap addressToCompilationMap; private final List<MaxCompilation> compilations = new ArrayList<MaxCompilation>(); private final List<TeleTargetMethod> teleTargetMethods = new ArrayList<TeleTargetMethod>(); private final RemoteObjectReferenceManager remoteObjectReferenceManager; private final UnmanagedCodeCacheRegionStatsPrinter localStatsPrinter; /** * Creates an object that models the region of the VM's code cache that is in the boot image. * @param vm the VM * @param teleCodeRegion the VM object that describes the memory allocated * @param codeCache the manager for code cache regions */ public VmBootCodeCacheRegion(TeleVM vm, TeleCodeRegion teleCodeRegion, VmCodeCacheAccess codeCache) { super(vm, teleCodeRegion); this.teleCodeRegion = teleCodeRegion; this.inspectableObjects = new ArrayList<MaxObject>(); this.inspectableObjects.add(teleCodeRegion); this.codeCache = codeCache; this.entityDescription = "The boot image area " + teleCodeRegion.getRegionName() + " owned by the VM code cache"; this.addressToCompilationMap = new AddressToCompilationMap(vm); this.remoteObjectReferenceManager = new UnmanagedCodeCacheRemoteReferenceManager(vm, this); this.codePointerManager = new UnmanagedRemoteCodePointerManager(vm, this); this.localStatsPrinter = new UnmanagedCodeCacheRegionStatsPrinter(); this.updateTracer = new TimedTrace(TRACE_VALUE, tracePrefix() + "updating name=" + teleCodeRegion.getRegionName()); Trace.line(TRACE_VALUE, tracePrefix() + "code cache region created for " + teleCodeRegion.getRegionName() + " with " + remoteObjectReferenceManager.getClass().getSimpleName()); } /** * {@inheritDoc} * <p> * Proactively attempt to discover every method compilation in the region upon * refresh. It is slightly possible, however, that a {@link TeleTargetMethod} * might be created in some other way, before we locate it here. For that reason, * new ones are registered by a call from the constructor for {@link TeleTargetMethod}. * <p> * This implementation exploits the representation of {@link TargetMethod}s held in * a VM instance of {@link CodeRegion} as an array of {@link TargetMethod} * references. In theory, the contents of the boot code cache should not grow, but * we check anyway by checking the compilation count. */ public void updateCache(long epoch) { updateTracer.begin(); // Ensure any updating of the object's state is done. teleCodeRegion.updateCache(epoch); if (teleCodeRegion.isAllocated()) { final int vmTargetMethodCount = teleCodeRegion.nTargetMethods(); int registeredTargetMethodCount = teleTargetMethods.size(); while (registeredTargetMethodCount < vmTargetMethodCount) { RemoteReference targetMethodReference = teleCodeRegion.getTargetMethodReference(registeredTargetMethodCount++); // Creating a {@link TeleTargetMethod} causes it to be added to the code registry TeleTargetMethod teleTargetMethod = (TeleTargetMethod) objects().makeTeleObject(targetMethodReference); if (teleTargetMethod == null) { vm().invalidReferencesLogger().record(targetMethodReference, TeleTargetMethod.class); continue; } teleTargetMethods.add(teleTargetMethod); } } updateTracer.end(localStatsPrinter); } public String entityDescription() { return entityDescription; } public int compilationCount() { return teleTargetMethods.size(); } /** * {@inheritDoc} * <p> * Assume that compilations in the boot code cache are allocated linearly, and that they are never relocated or evicted. */ public List<MaxCompilation> compilations() { TeleError.check(compilations.size() <= teleTargetMethods.size(), "Compilations in boot code cache appear to have disappeared"); if (compilations.size() < teleTargetMethods.size()) { for (int index = compilations.size(); index < teleTargetMethods.size(); index++) { compilations.add(findCompilation(teleTargetMethods.get(index).getRegionStart())); } } return Collections.unmodifiableList(compilations); } @Override public int loadedCompilationCount() { int count = 0; for (TeleTargetMethod teleTargetMethod : teleTargetMethods) { if (teleTargetMethod.isCacheLoaded()) { count++; } } return count; } /** * {@inheritDoc} * <p> * This method only gets called when a new instance of {@link TeleTargetMethod} gets created, * so assume that there has not yet been a {@link TeleCompilation} created for it. */ @Override public void register(TeleTargetMethod teleTargetMethod) { TeleError.check(contains(teleTargetMethod.getRegionStart()), "Attempt to register TargetMethod in the wrong region"); addressToCompilationMap.add(new TeleCompilation(vm(), teleTargetMethod, codeCache)); } @Override public TeleCompilation findCompilation(Address address) { return addressToCompilationMap.find(address); } @Override public void writeSummary(PrintStream printStream) { addressToCompilationMap.writeSummary(printStream); } public RemoteObjectReferenceManager objectReferenceManager() { return remoteObjectReferenceManager; } public RemoteCodePointerManager codePointerManager() { return codePointerManager; } @Override public List<MaxObject> inspectableObjects() { return inspectableObjects; } }