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 }