1 /*
   2  * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 package sun.jvm.hotspot.code;
  26 
  27 import java.util.*;
  28 import sun.jvm.hotspot.debugger.*;
  29 import sun.jvm.hotspot.memory.*;
  30 import sun.jvm.hotspot.runtime.*;
  31 import sun.jvm.hotspot.types.*;
  32 import sun.jvm.hotspot.utilities.*;
  33 
  34 public class CodeCache {
  35   private static GrowableArray<CodeHeap> heapArray;
  36   private static AddressField scavengeRootNMethodsField;
  37   private static VirtualConstructor virtualConstructor;
  38 
  39   static {
  40     VM.registerVMInitializedObserver(new Observer() {
  41         public void update(Observable o, Object data) {
  42           initialize(VM.getVM().getTypeDataBase());
  43         }
  44       });
  45   }
  46 
  47   private static synchronized void initialize(TypeDataBase db) {
  48     Type type = db.lookupType("CodeCache");
  49 
  50     // Get array of CodeHeaps
  51     // Note: CodeHeap may be subclassed with optional private heap mechanisms.
  52     Type codeHeapType = db.lookupType("CodeHeap");
  53     VirtualBaseConstructor heapConstructor =
  54         new VirtualBaseConstructor(db, codeHeapType, "sun.jvm.hotspot.memory", CodeHeap.class);
  55 
  56     AddressField heapsField = type.getAddressField("_heaps");
  57     heapArray = GrowableArray.create(heapsField.getValue(), heapConstructor);
  58 
  59     scavengeRootNMethodsField = type.getAddressField("_scavenge_root_nmethods");
  60 
  61     virtualConstructor = new VirtualConstructor(db);
  62     // Add mappings for all possible CodeBlob subclasses
  63     virtualConstructor.addMapping("BufferBlob", BufferBlob.class);
  64     virtualConstructor.addMapping("nmethod", NMethod.class);
  65     virtualConstructor.addMapping("RuntimeStub", RuntimeStub.class);
  66     virtualConstructor.addMapping("AdapterBlob", AdapterBlob.class);
  67     virtualConstructor.addMapping("MethodHandlesAdapterBlob", MethodHandlesAdapterBlob.class);
  68     virtualConstructor.addMapping("SafepointBlob", SafepointBlob.class);
  69     virtualConstructor.addMapping("DeoptimizationBlob", DeoptimizationBlob.class);
  70     if (VM.getVM().isServerCompiler()) {
  71       virtualConstructor.addMapping("ExceptionBlob", ExceptionBlob.class);
  72       virtualConstructor.addMapping("UncommonTrapBlob", UncommonTrapBlob.class);
  73     }
  74   }
  75 
  76   public NMethod scavengeRootMethods() {
  77     return (NMethod) VMObjectFactory.newObject(NMethod.class, scavengeRootNMethodsField.getValue());
  78   }
  79 
  80   public boolean contains(Address p) {
  81     for (int i = 0; i < heapArray.length(); ++i) {
  82       if (heapArray.at(i).contains(p)) {
  83         return true;
  84       }
  85     }
  86     return false;
  87   }
  88 
  89   /** When VM.getVM().isDebugging() returns true, this behaves like
  90       findBlobUnsafe */
  91   public CodeBlob findBlob(Address start) {
  92     CodeBlob result = findBlobUnsafe(start);
  93     if (result == null) return null;
  94     if (VM.getVM().isDebugging()) {
  95       return result;
  96     }
  97     // We could potientially look up non_entrant methods
  98     // NOTE: this is effectively a "guarantee", and is slightly different from the one in the VM
  99     if (Assert.ASSERTS_ENABLED) {
 100       Assert.that(!(result.isZombie() || result.isLockedByVM()), "unsafe access to zombie method");
 101     }
 102     return result;
 103   }
 104 
 105   public CodeBlob findBlobUnsafe(Address start) {
 106     CodeBlob result = null;
 107     CodeHeap containing_heap = null;
 108     for (int i = 0; i < heapArray.length(); ++i) {
 109       if (heapArray.at(i).contains(start)) {
 110         containing_heap = heapArray.at(i);
 111         break;
 112       }
 113     }
 114     if (containing_heap == null) {
 115       return null;
 116     }
 117 
 118     try {
 119       result = (CodeBlob) virtualConstructor.instantiateWrapperFor(containing_heap.findStart(start));
 120     }
 121     catch (WrongTypeException wte) {
 122       Address cbAddr = null;
 123       try {
 124         cbAddr = containing_heap.findStart(start);
 125       }
 126       catch (Exception findEx) {
 127         findEx.printStackTrace();
 128       }
 129 
 130       String message = "Couldn't deduce type of CodeBlob ";
 131       if (cbAddr != null) {
 132         message = message + "@" + cbAddr + " ";
 133       }
 134       message = message + "for PC=" + start;
 135 
 136       throw new RuntimeException(message, wte);
 137     }
 138     if (result == null) return null;
 139     if (Assert.ASSERTS_ENABLED) {
 140       // The HeapBlock that contains this blob is outside of the blob
 141       // but it shouldn't be an error to find a blob based on the
 142       // pointer to the HeapBlock.
 143       Assert.that(result.blobContains(start) || result.blobContains(start.addOffsetTo(8)),
 144                                                                     "found wrong CodeBlob");
 145     }
 146     return result;
 147   }
 148 
 149   public NMethod findNMethod(Address start) {
 150     CodeBlob cb = findBlob(start);
 151     if (Assert.ASSERTS_ENABLED) {
 152       Assert.that(cb == null || cb.isNMethod(), "did not find an nmethod");
 153     }
 154     return (NMethod) cb;
 155   }
 156 
 157   public NMethod findNMethodUnsafe(Address start) {
 158     CodeBlob cb = findBlobUnsafe(start);
 159     if (Assert.ASSERTS_ENABLED) {
 160       Assert.that(cb == null || cb.isNMethod(), "did not find an nmethod");
 161     }
 162     return (NMethod) cb;
 163   }
 164 
 165   /** Routine for instantiating appropriately-typed wrapper for a
 166       CodeBlob. Used by CodeCache, Runtime1, etc. */
 167   public CodeBlob createCodeBlobWrapper(Address codeBlobAddr) {
 168     try {
 169       return (CodeBlob) virtualConstructor.instantiateWrapperFor(codeBlobAddr);
 170     }
 171     catch (Exception e) {
 172       String message = "Unable to deduce type of CodeBlob from address " + codeBlobAddr +
 173                        " (expected type nmethod, RuntimeStub, ";
 174       if (VM.getVM().isClientCompiler()) {
 175         message = message + " or ";
 176       }
 177       message = message + "SafepointBlob";
 178       if (VM.getVM().isServerCompiler()) {
 179         message = message + ", DeoptimizationBlob, or ExceptionBlob";
 180       }
 181       message = message + ")";
 182       throw new RuntimeException(message);
 183     }
 184   }
 185 
 186   public void iterate(CodeCacheVisitor visitor) {
 187     visitor.prologue(lowBound(), highBound());
 188     for (int i = 0; i < heapArray.length(); ++i) {
 189       CodeHeap current_heap = heapArray.at(i);
 190       current_heap.iterate(visitor, this);
 191     }
 192     visitor.epilogue();
 193   }
 194 
 195   //--------------------------------------------------------------------------------
 196   // Internals only below this point
 197   //
 198 
 199   private Address lowBound() {
 200     Address low = heapArray.at(0).begin();
 201     for (int i = 1; i < heapArray.length(); ++i) {
 202       if (heapArray.at(i).begin().lessThan(low)) {
 203         low = heapArray.at(i).begin();
 204       }
 205     }
 206     return low;
 207   }
 208 
 209   private Address highBound() {
 210     Address high = heapArray.at(0).end();
 211     for (int i = 1; i < heapArray.length(); ++i) {
 212       if (heapArray.at(i).end().greaterThan(high)) {
 213         high = heapArray.at(i).end();
 214       }
 215     }
 216     return high;
 217   }
 218 }