1 /* 2 * Copyright (c) 2016, 2017, 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 package jdk.tools.jaotc; 25 26 import java.util.concurrent.atomic.AtomicInteger; 27 import java.util.HashMap; 28 import java.util.HashSet; 29 30 import jdk.tools.jaotc.binformat.BinaryContainer; 31 import jdk.tools.jaotc.binformat.ReadOnlyDataContainer; 32 import jdk.tools.jaotc.AOTCompiledClass.AOTKlassData; 33 import org.graalvm.compiler.code.CompilationResult; 34 35 import jdk.vm.ci.code.site.Mark; 36 import jdk.vm.ci.code.site.Site; 37 import jdk.vm.ci.hotspot.HotSpotCompiledCode; 38 import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; 39 40 final class CompiledMethodInfo { 41 42 private static final int UNINITIALIZED_OFFSET = -1; 43 44 private static class AOTMethodOffsets { 45 /** 46 * Offset in metaspace names section. 47 */ 48 private int nameOffset; 49 50 /** 51 * Offset in the text section at which compiled code starts. 52 */ 53 private int textSectionOffset; 54 55 /** 56 * Offset in the metadata section. 57 */ 58 private int metadataOffset; 59 60 /** 61 * Offset to the metadata in the GOT table. 62 */ 63 private int metadataGotOffset; 64 65 /** 66 * Size of the metadata. 67 */ 68 private int metadataGotSize; 69 70 /** 71 * The sequential number corresponding to the order of methods code in code buffer. 72 */ 73 private int codeId; 74 75 AOTMethodOffsets() { 76 this.nameOffset = UNINITIALIZED_OFFSET; 77 this.textSectionOffset = UNINITIALIZED_OFFSET; 78 this.metadataOffset = UNINITIALIZED_OFFSET; 79 this.metadataGotOffset = UNINITIALIZED_OFFSET; 80 this.metadataGotSize = -1; 81 this.codeId = -1; 82 } 83 84 void addMethodOffsets(ReadOnlyDataContainer container, String name) { 85 verify(name); 86 // @formatter:off 87 /* 88 * The offsets layout should match AOTMethodOffsets structure in AOT JVM runtime 89 */ 90 // Add the offset to the name in the .metaspace.names section 91 container.appendInt(nameOffset). 92 // Add the offset to the code in the .text section 93 appendInt(textSectionOffset). 94 // Add the offset to the metadata in the .method.metadata section 95 appendInt(metadataOffset). 96 // Add the offset to the metadata in the .metadata.got section 97 appendInt(metadataGotOffset). 98 // Add the size of the metadata 99 appendInt(metadataGotSize). 100 // Add code ID. 101 appendInt(codeId); 102 // @formatter:on 103 } 104 105 private void verify(String name) { 106 assert nameOffset >= 0 : "incorrect nameOffset: " + nameOffset + " for method: " + name; 107 assert textSectionOffset > 0 : "incorrect textSectionOffset: " + textSectionOffset + " for method: " + name; 108 assert metadataOffset >= 0 : "incorrect metadataOffset: " + metadataOffset + " for method: " + name; 109 assert metadataGotOffset >= 0 : "incorrect metadataGotOffset: " + metadataGotOffset + " for method: " + name; 110 assert metadataGotSize >= 0 : "incorrect metadataGotSize: " + metadataGotSize + " for method: " + name; 111 assert codeId >= 0 : "incorrect codeId: " + codeId + " for method: " + name; 112 } 113 114 protected void setNameOffset(int offset) { 115 nameOffset = offset; 116 } 117 118 protected void setTextSectionOffset(int textSectionOffset) { 119 this.textSectionOffset = textSectionOffset; 120 } 121 122 protected int getTextSectionOffset() { 123 return textSectionOffset; 124 } 125 126 protected void setCodeId(int codeId) { 127 this.codeId = codeId; 128 } 129 130 protected int getCodeId() { 131 return codeId; 132 } 133 134 protected void setMetadataOffset(int offset) { 135 metadataOffset = offset; 136 } 137 138 protected void setMetadataGotOffset(int metadataGotOffset) { 139 this.metadataGotOffset = metadataGotOffset; 140 } 141 142 protected void setMetadataGotSize(int length) { 143 this.metadataGotSize = length; 144 } 145 } 146 147 /** 148 * Method name 149 */ 150 private String name; 151 152 /** 153 * Result of graal compilation. 154 */ 155 private CompilationResult compilationResult; 156 157 /** 158 * HotSpotResolvedJavaMethod or Stub corresponding to the compilation result. 159 */ 160 private JavaMethodInfo methodInfo; 161 162 /** 163 * Compiled code from installation. 164 */ 165 private HotSpotCompiledCode code; 166 167 /** 168 * Offset to stubs. 169 */ 170 private int stubsOffset; 171 172 /** 173 * The total size in bytes of the stub section. 174 */ 175 private int totalStubSize; 176 177 /** 178 * Method's offsets. 179 */ 180 private AOTMethodOffsets methodOffsets; 181 182 /** 183 * List of stubs (PLT trampoline). 184 */ 185 private HashMap<String, StubInformation> stubs = new HashMap<>(); 186 187 /** 188 * List of referenced classes. 189 */ 190 private HashSet<AOTKlassData> dependentKlasses = new HashSet<>(); 191 192 /** 193 * Methods count used to generate unique global method id. 194 */ 195 private static final AtomicInteger methodsCount = new AtomicInteger(); 196 197 CompiledMethodInfo(CompilationResult compilationResult, JavaMethodInfo methodInfo) { 198 this.name = methodInfo.getNameAndSignature(); 199 this.compilationResult = compilationResult; 200 this.methodInfo = methodInfo; 201 this.stubsOffset = UNINITIALIZED_OFFSET; 202 this.methodOffsets = new AOTMethodOffsets(); 203 } 204 205 String name() { 206 return name; 207 } 208 209 void addMethodOffsets(BinaryContainer binaryContainer, ReadOnlyDataContainer container) { 210 this.methodOffsets.setNameOffset(binaryContainer.addMetaspaceName(name)); 211 this.methodOffsets.addMethodOffsets(container, name); 212 for (AOTKlassData data : dependentKlasses) { 213 data.addDependentMethod(this); 214 } 215 } 216 217 CompilationResult getCompilationResult() { 218 return compilationResult; 219 } 220 221 JavaMethodInfo getMethodInfo() { 222 return methodInfo; 223 } 224 225 void setTextSectionOffset(int textSectionOffset) { 226 methodOffsets.setTextSectionOffset(textSectionOffset); 227 } 228 229 public int getTextSectionOffset() { 230 return methodOffsets.getTextSectionOffset(); 231 } 232 233 void setCodeId() { 234 methodOffsets.setCodeId(CompiledMethodInfo.getNextCodeId()); 235 } 236 237 int getCodeId() { 238 return this.methodOffsets.getCodeId(); 239 } 240 241 static int getMethodsCount() { 242 return methodsCount.get(); 243 } 244 245 static int getNextCodeId() { 246 return methodsCount.getAndIncrement(); 247 } 248 249 int getCodeSize() { 250 return stubsOffset + getStubCodeSize(); 251 } 252 253 int getStubCodeSize() { 254 return totalStubSize; 255 } 256 257 void setMetadataOffset(int offset) { 258 this.methodOffsets.setMetadataOffset(offset); 259 } 260 261 /** 262 * Offset into the code of this method where the stub section starts. 263 */ 264 void setStubsOffset(int offset) { 265 stubsOffset = offset; 266 } 267 268 int getStubsOffset() { 269 return stubsOffset; 270 } 271 272 void setMetadataGotOffset(int metadataGotOffset) { 273 this.methodOffsets.setMetadataGotOffset(metadataGotOffset); 274 } 275 276 void setMetadataGotSize(int length) { 277 this.methodOffsets.setMetadataGotSize(length); 278 } 279 280 void addStubCode(String call, StubInformation stub) { 281 stubs.put(call, stub); 282 totalStubSize += stub.getSize(); 283 } 284 285 StubInformation getStubFor(String call) { 286 StubInformation stub = stubs.get(call); 287 assert stub != null : "missing stub for call " + call; 288 stub.verify(); 289 return stub; 290 } 291 292 void addDependentKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) { 293 AOTKlassData klassData = AOTCompiledClass.addFingerprintKlassData(binaryContainer, type); 294 dependentKlasses.add(klassData); 295 } 296 297 AOTKlassData getDependentKlassData(HotSpotResolvedObjectType type) { 298 AOTKlassData klassData = AOTCompiledClass.getAOTKlassData(type); 299 if (dependentKlasses.contains(klassData)) { 300 return klassData; 301 } 302 return null; 303 } 304 305 boolean hasMark(Site call, MarkId id) { 306 for (Mark m : compilationResult.getMarks()) { 307 // TODO: X64-specific code. 308 // Call instructions are aligned to 8 309 // bytes - 1 on x86 to patch address atomically, 310 int adjOffset = (m.pcOffset & (-8)) + 7; 311 // Mark points before aligning nops. 312 if ((call.pcOffset == adjOffset) && MarkId.getEnum((int) m.id) == id) { 313 return true; 314 } 315 } 316 return false; 317 } 318 319 String asTag() { 320 return "[" + methodInfo.getSymbolName() + "]"; 321 } 322 323 HotSpotCompiledCode compiledCode() { 324 if (code == null) { 325 code = methodInfo.compiledCode(compilationResult); 326 } 327 return code; 328 } 329 330 // Free memory 331 void clear() { 332 this.dependentKlasses = null; 333 this.name = null; 334 } 335 336 void clearCompileData() { 337 this.code = null; 338 this.stubs = null; 339 this.compilationResult = null; 340 this.methodInfo = null; 341 } 342 }