1 /*
   2  * Copyright (c) 2000, 2019, 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 VirtualConstructor virtualConstructor;
  37 
  38   static {
  39     VM.registerVMInitializedObserver(new Observer() {
  40         public void update(Observable o, Object data) {
  41           initialize(VM.getVM().getTypeDataBase());
  42         }
  43       });
  44   }
  45 
  46   private static synchronized void initialize(TypeDataBase db) {
  47     Type type = db.lookupType("CodeCache");
  48 
  49     // Get array of CodeHeaps
  50     // Note: CodeHeap may be subclassed with optional private heap mechanisms.
  51     Type codeHeapType = db.lookupType("CodeHeap");
  52     VirtualBaseConstructor heapConstructor =
  53         new VirtualBaseConstructor(db, codeHeapType, "sun.jvm.hotspot.memory", CodeHeap.class);
  54 
  55     AddressField heapsField = type.getAddressField("_heaps");
  56     heapArray = GrowableArray.create(heapsField.getValue(), heapConstructor);
  57 
  58     virtualConstructor = new VirtualConstructor(db);
  59     // Add mappings for all possible CodeBlob subclasses
  60     virtualConstructor.addMapping("BufferBlob", BufferBlob.class);
  61     virtualConstructor.addMapping("nmethod", NMethod.class);
  62     virtualConstructor.addMapping("RuntimeStub", RuntimeStub.class);
  63     virtualConstructor.addMapping("AdapterBlob", AdapterBlob.class);
  64     virtualConstructor.addMapping("MethodHandlesAdapterBlob", MethodHandlesAdapterBlob.class);
  65     virtualConstructor.addMapping("SafepointBlob", SafepointBlob.class);
  66     virtualConstructor.addMapping("DeoptimizationBlob", DeoptimizationBlob.class);
  67     if (VM.getVM().isServerCompiler()) {
  68       virtualConstructor.addMapping("ExceptionBlob", ExceptionBlob.class);
  69       virtualConstructor.addMapping("UncommonTrapBlob", UncommonTrapBlob.class);
  70     }
  71   }
  72 
  73   public boolean contains(Address p) {
  74     for (int i = 0; i < heapArray.length(); ++i) {
  75       if (heapArray.at(i).contains(p)) {
  76         return true;
  77       }
  78     }
  79     return false;
  80   }
  81 
  82   /** When VM.getVM().isDebugging() returns true, this behaves like
  83       findBlobUnsafe */
  84   public CodeBlob findBlob(Address start) {
  85     CodeBlob result = findBlobUnsafe(start);
  86     if (result == null) return null;
  87     if (VM.getVM().isDebugging()) {
  88       return result;
  89     }
  90     // We could potientially look up non_entrant methods
  91     // NOTE: this is effectively a "guarantee", and is slightly different from the one in the VM
  92     if (Assert.ASSERTS_ENABLED) {
  93       Assert.that(!(result.isZombie() || result.isLockedByVM()), "unsafe access to zombie method");
  94     }
  95     return result;
  96   }
  97 
  98   public CodeBlob findBlobUnsafe(Address start) {
  99     CodeBlob result = null;
 100     CodeHeap containing_heap = null;
 101     for (int i = 0; i < heapArray.length(); ++i) {
 102       if (heapArray.at(i).contains(start)) {
 103         containing_heap = heapArray.at(i);
 104         break;
 105       }
 106     }
 107     if (containing_heap == null) {
 108       return null;
 109     }
 110 
 111     try {
 112       result = (CodeBlob) virtualConstructor.instantiateWrapperFor(containing_heap.findStart(start));
 113     }
 114     catch (WrongTypeException wte) {
 115       Address cbAddr = null;
 116       try {
 117         cbAddr = containing_heap.findStart(start);
 118       }
 119       catch (Exception findEx) {
 120         findEx.printStackTrace();
 121       }
 122 
 123       String message = "Couldn't deduce type of CodeBlob ";
 124       if (cbAddr != null) {
 125         message = message + "@" + cbAddr + " ";
 126       }
 127       message = message + "for PC=" + start;
 128 
 129       throw new RuntimeException(message, wte);
 130     }
 131     if (result == null) return null;
 132     if (Assert.ASSERTS_ENABLED) {
 133       // The HeapBlock that contains this blob is outside of the blob
 134       // but it shouldn't be an error to find a blob based on the
 135       // pointer to the HeapBlock.
 136       Assert.that(result.blobContains(start) || result.blobContains(start.addOffsetTo(8)),
 137                                                                     "found wrong CodeBlob");
 138     }
 139     return result;
 140   }
 141 
 142   public NMethod findNMethod(Address start) {
 143     CodeBlob cb = findBlob(start);
 144     if (Assert.ASSERTS_ENABLED) {
 145       Assert.that(cb == null || cb.isNMethod(), "did not find an nmethod");
 146     }
 147     return (NMethod) cb;
 148   }
 149 
 150   public NMethod findNMethodUnsafe(Address start) {
 151     CodeBlob cb = findBlobUnsafe(start);
 152     if (Assert.ASSERTS_ENABLED) {
 153       Assert.that(cb == null || cb.isNMethod(), "did not find an nmethod");
 154     }
 155     return (NMethod) cb;
 156   }
 157 
 158   /** Routine for instantiating appropriately-typed wrapper for a
 159       CodeBlob. Used by CodeCache, Runtime1, etc. */
 160   public CodeBlob createCodeBlobWrapper(Address codeBlobAddr) {
 161     try {
 162       return (CodeBlob) virtualConstructor.instantiateWrapperFor(codeBlobAddr);
 163     }
 164     catch (Exception e) {
 165       String message = "Unable to deduce type of CodeBlob from address " + codeBlobAddr +
 166                        " (expected type nmethod, RuntimeStub, ";
 167       if (VM.getVM().isClientCompiler()) {
 168         message = message + " or ";
 169       }
 170       message = message + "SafepointBlob";
 171       if (VM.getVM().isServerCompiler()) {
 172         message = message + ", DeoptimizationBlob, or ExceptionBlob";
 173       }
 174       message = message + ")";
 175       throw new RuntimeException(message);
 176     }
 177   }
 178 
 179   public void iterate(CodeCacheVisitor visitor) {
 180     visitor.prologue(lowBound(), highBound());
 181     for (int i = 0; i < heapArray.length(); ++i) {
 182       CodeHeap current_heap = heapArray.at(i);
 183       current_heap.iterate(visitor, this);
 184     }
 185     visitor.epilogue();
 186   }
 187 
 188   //--------------------------------------------------------------------------------
 189   // Internals only below this point
 190   //
 191 
 192   private Address lowBound() {
 193     Address low = heapArray.at(0).begin();
 194     for (int i = 1; i < heapArray.length(); ++i) {
 195       if (heapArray.at(i).begin().lessThan(low)) {
 196         low = heapArray.at(i).begin();
 197       }
 198     }
 199     return low;
 200   }
 201 
 202   private Address highBound() {
 203     Address high = heapArray.at(0).end();
 204     for (int i = 1; i < heapArray.length(); ++i) {
 205       if (heapArray.at(i).end().greaterThan(high)) {
 206         high = heapArray.at(i).end();
 207       }
 208     }
 209     return high;
 210   }
 211 }