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