1 /*
   2  * Copyright (c) 2000, 2012, 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     AddressField heapsField = type.getAddressField("_heaps");
  52     heapArray = GrowableArray.create(heapsField.getValue(), new StaticBaseConstructor<CodeHeap>(CodeHeap.class));
  53 
  54     scavengeRootNMethodsField = type.getAddressField("_scavenge_root_nmethods");
  55 
  56     virtualConstructor = new VirtualConstructor(db);
  57     // Add mappings for all possible CodeBlob subclasses
  58     virtualConstructor.addMapping("BufferBlob", BufferBlob.class);
  59     virtualConstructor.addMapping("nmethod", NMethod.class);
  60     virtualConstructor.addMapping("RuntimeStub", RuntimeStub.class);
  61     virtualConstructor.addMapping("AdapterBlob", AdapterBlob.class);
  62     virtualConstructor.addMapping("MethodHandlesAdapterBlob", MethodHandlesAdapterBlob.class);
  63     virtualConstructor.addMapping("SafepointBlob", SafepointBlob.class);
  64     virtualConstructor.addMapping("DeoptimizationBlob", DeoptimizationBlob.class);
  65     if (VM.getVM().isServerCompiler()) {
  66       virtualConstructor.addMapping("ExceptionBlob", ExceptionBlob.class);
  67       virtualConstructor.addMapping("UncommonTrapBlob", UncommonTrapBlob.class);
  68     }
  69   }
  70 
  71   public NMethod scavengeRootMethods() {
  72     return (NMethod) VMObjectFactory.newObject(NMethod.class, scavengeRootNMethodsField.getValue());
  73   }
  74 
  75   public boolean contains(Address p) {
  76     for (int i = 0; i < heapArray.length(); ++i) {
  77       if (heapArray.at(i).contains(p)) {
  78         return true;
  79       }
  80     }
  81     return false;
  82   }
  83 
  84   /** When VM.getVM().isDebugging() returns true, this behaves like
  85       findBlobUnsafe */
  86   public CodeBlob findBlob(Address start) {
  87     CodeBlob result = findBlobUnsafe(start);
  88     if (result == null) return null;
  89     if (VM.getVM().isDebugging()) {
  90       return result;
  91     }
  92     // We could potientially look up non_entrant methods
  93     // NOTE: this is effectively a "guarantee", and is slightly different from the one in the VM
  94     if (Assert.ASSERTS_ENABLED) {
  95       Assert.that(!(result.isZombie() || result.isLockedByVM()), "unsafe access to zombie method");
  96     }
  97     return result;
  98   }
  99 
 100   public CodeBlob findBlobUnsafe(Address start) {
 101     CodeBlob result = null;
 102     CodeHeap containing_heap = null;
 103     for (int i = 0; i < heapArray.length(); ++i) {
 104       if (heapArray.at(i).contains(start)) {
 105         containing_heap = heapArray.at(i);
 106         break;
 107       }
 108     }
 109     if (containing_heap == null) {
 110       return null;
 111     }
 112     
 113     try {
 114       result = (CodeBlob) virtualConstructor.instantiateWrapperFor(containing_heap.findStart(start));
 115     }
 116     catch (WrongTypeException wte) {
 117       Address cbAddr = null;
 118       try {
 119         cbAddr = containing_heap.findStart(start);
 120       }
 121       catch (Exception findEx) {
 122         findEx.printStackTrace();
 123       }
 124 
 125       String message = "Couldn't deduce type of CodeBlob ";
 126       if (cbAddr != null) {
 127         message = message + "@" + cbAddr + " ";
 128       }
 129       message = message + "for PC=" + start;
 130 
 131       throw new RuntimeException(message, wte);
 132     }
 133     if (result == null) return null;
 134     if (Assert.ASSERTS_ENABLED) {
 135       // The HeapBlock that contains this blob is outside of the blob
 136       // but it shouldn't be an error to find a blob based on the
 137       // pointer to the HeapBlock.
 138       Assert.that(result.blobContains(start) || result.blobContains(start.addOffsetTo(8)),
 139                                                                     "found wrong CodeBlob");
 140     }
 141     return result;
 142   }
 143 
 144   public NMethod findNMethod(Address start) {
 145     CodeBlob cb = findBlob(start);
 146     if (Assert.ASSERTS_ENABLED) {
 147       Assert.that(cb == null || cb.isNMethod(), "did not find an nmethod");
 148     }
 149     return (NMethod) cb;
 150   }
 151 
 152   public NMethod findNMethodUnsafe(Address start) {
 153     CodeBlob cb = findBlobUnsafe(start);
 154     if (Assert.ASSERTS_ENABLED) {
 155       Assert.that(cb == null || cb.isNMethod(), "did not find an nmethod");
 156     }
 157     return (NMethod) cb;
 158   }
 159 
 160   /** Routine for instantiating appropriately-typed wrapper for a
 161       CodeBlob. Used by CodeCache, Runtime1, etc. */
 162   public CodeBlob createCodeBlobWrapper(Address codeBlobAddr) {
 163     try {
 164       return (CodeBlob) virtualConstructor.instantiateWrapperFor(codeBlobAddr);
 165     }
 166     catch (Exception e) {
 167       String message = "Unable to deduce type of CodeBlob from address " + codeBlobAddr +
 168                        " (expected type nmethod, RuntimeStub, ";
 169       if (VM.getVM().isClientCompiler()) {
 170         message = message + " or ";
 171       }
 172       message = message + "SafepointBlob";
 173       if (VM.getVM().isServerCompiler()) {
 174         message = message + ", DeoptimizationBlob, or ExceptionBlob";
 175       }
 176       message = message + ")";
 177       throw new RuntimeException(message);
 178     }
 179   }
 180 
 181   public void iterate(CodeCacheVisitor visitor) {
 182     visitor.prologue(lowBound(), highBound());
 183     CodeBlob lastBlob = null;
 184     
 185     for (int i = 0; i < heapArray.length(); ++i) {
 186       CodeHeap current_heap = heapArray.at(i);
 187       Address ptr = current_heap.begin();
 188       while (ptr != null && ptr.lessThan(current_heap.end())) {
 189         try {
 190           // Use findStart to get a pointer inside blob other findBlob asserts
 191           CodeBlob blob = findBlobUnsafe(current_heap.findStart(ptr));
 192           if (blob != null) {
 193             visitor.visit(blob);
 194             if (blob == lastBlob) {
 195               throw new InternalError("saw same blob twice");
 196             }
 197             lastBlob = blob;
 198           }
 199         } catch (RuntimeException e) {
 200           e.printStackTrace();
 201         }
 202         Address next = current_heap.nextBlock(ptr);
 203         if (next != null && next.lessThan(ptr)) {
 204           throw new InternalError("pointer moved backwards");
 205         }
 206         ptr = next;
 207       }
 208     }
 209     visitor.epilogue();
 210   }
 211 
 212   //--------------------------------------------------------------------------------
 213   // Internals only below this point
 214   //
 215   
 216   private Address lowBound() {
 217     Address low = heapArray.at(0).begin();
 218     for (int i = 1; i < heapArray.length(); ++i) {
 219       if (heapArray.at(i).begin().lessThan(low)) {
 220         low = heapArray.at(i).begin();
 221       }
 222     }
 223     return low;
 224   }
 225   
 226   private Address highBound() {
 227     Address high = heapArray.at(0).end();
 228     for (int i = 1; i < heapArray.length(); ++i) {
 229       if (heapArray.at(i).end().greaterThan(high)) {
 230         high = heapArray.at(i).end();
 231       }
 232     }
 233     return high;
 234   }
 235 }