1 /* 2 * Copyright (c) 2016, 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.Map; 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 public class CompiledMethodInfo { 41 42 public static class StubInformation { 43 int stubOffset; // the offset inside the code (text + stubOffset) 44 int stubSize; // the stub size 45 int dispatchJumpOffset; // offset after main dispatch jump instruction 46 int resolveJumpOffset; // offset after jump instruction to runtime call resolution 47 // function. 48 int resolveJumpStart; // offset of jump instruction to VM runtime call resolution 49 // function. 50 int c2iJumpOffset; // offset after jump instruction to c2i adapter for static calls. 51 int movOffset; // offset after move instruction which loads from got cell: 52 // - Method* for static call 53 // - Klass* for virtual call 54 55 boolean isVirtual; // virtual call stub 56 57 // maybe add type of stub as well, right now we only have static stubs 58 59 public StubInformation(int stubOffset, boolean isVirtual) { 60 this.stubOffset = stubOffset; 61 this.isVirtual = isVirtual; 62 this.stubSize = -1; 63 this.movOffset = -1; 64 this.c2iJumpOffset = -1; 65 this.resolveJumpOffset = -1; 66 this.resolveJumpStart = -1; 67 this.dispatchJumpOffset = -1; 68 } 69 70 public int getOffset() { 71 return stubOffset; 72 } 73 74 public boolean isVirtual() { 75 return isVirtual; 76 } 77 78 public void setSize(int stubSize) { 79 this.stubSize = stubSize; 80 } 81 82 public int getSize() { 83 return stubSize; 84 } 85 86 public void setMovOffset(int movOffset) { 87 this.movOffset = movOffset + stubOffset; 88 } 89 90 public int getMovOffset() { 91 return movOffset; 92 } 93 94 public void setC2IJumpOffset(int c2iJumpOffset) { 95 this.c2iJumpOffset = c2iJumpOffset + stubOffset; 96 } 97 98 public int getC2IJumpOffset() { 99 return c2iJumpOffset; 100 } 101 102 public void setResolveJumpOffset(int resolveJumpOffset) { 103 this.resolveJumpOffset = resolveJumpOffset + stubOffset; 104 } 105 106 public int getResolveJumpOffset() { 107 return resolveJumpOffset; 108 } 109 110 public void setResolveJumpStart(int resolveJumpStart) { 111 this.resolveJumpStart = resolveJumpStart + stubOffset; 112 } 113 114 public int getResolveJumpStart() { 115 return resolveJumpStart; 116 } 117 118 public void setDispatchJumpOffset(int dispatchJumpOffset) { 119 this.dispatchJumpOffset = dispatchJumpOffset + stubOffset; 120 } 121 122 public int getDispatchJumpOffset() { 123 return dispatchJumpOffset; 124 } 125 126 public void verify() { 127 assert stubOffset > 0 : "incorrect stubOffset: " + stubOffset; 128 assert stubSize > 0 : "incorrect stubSize: " + stubSize; 129 assert movOffset > 0 : "incorrect movOffset: " + movOffset; 130 assert dispatchJumpOffset > 0 : "incorrect dispatchJumpOffset: " + dispatchJumpOffset; 131 assert resolveJumpStart > 0 : "incorrect resolveJumpStart: " + resolveJumpStart; 132 assert resolveJumpOffset > 0 : "incorrect resolveJumpOffset: " + resolveJumpOffset; 133 if (!isVirtual) { 134 assert c2iJumpOffset > 0 : "incorrect c2iJumpOffset: " + c2iJumpOffset; 135 } 136 } 137 } 138 139 private static final int UNINITIALIZED_OFFSET = -1; 140 141 private static class AOTMethodOffsets { 142 /** 143 * Offset in metaspace names section. 144 */ 145 private int nameOffset; 146 147 /** 148 * Offset in the text section at which compiled code starts. 149 */ 150 private int textSectionOffset; 151 152 /** 153 * Offset in the metadata section. 154 */ 155 private int metadataOffset; 156 157 /** 158 * Offset to the metadata in the GOT table. 159 */ 160 private int metadataGotOffset; 161 162 /** 163 * Size of the metadata. 164 */ 165 private int metadataGotSize; 166 167 /** 168 * The sequential number corresponding to the order of methods code in code buffer. 169 */ 170 private int codeId; 171 172 public AOTMethodOffsets() { 173 this.nameOffset = UNINITIALIZED_OFFSET; 174 this.textSectionOffset = UNINITIALIZED_OFFSET; 175 this.metadataOffset = UNINITIALIZED_OFFSET; 176 this.metadataGotOffset = UNINITIALIZED_OFFSET; 177 this.metadataGotSize = -1; 178 this.codeId = -1; 179 } 180 181 protected void addMethodOffsets(ReadOnlyDataContainer container, String name) { 182 verify(name); 183 // @formatter:off 184 /* 185 * The offsets layout should match AOTMethodOffsets structure in AOT JVM runtime 186 */ 187 // Add the offset to the name in the .metaspace.names section 188 container.appendInt(nameOffset). 189 // Add the offset to the code in the .text section 190 appendInt(textSectionOffset). 191 // Add the offset to the metadata in the .method.metadata section 192 appendInt(metadataOffset). 193 // Add the offset to the metadata in the .metadata.got section 194 appendInt(metadataGotOffset). 195 // Add the size of the metadata 196 appendInt(metadataGotSize). 197 // Add code ID. 198 appendInt(codeId); 199 // @formatter:on 200 } 201 274 /** 275 * Method's offsets. 276 */ 277 private AOTMethodOffsets methodOffsets; 278 279 /** 280 * List of stubs (PLT trampoline). 281 */ 282 private Map<String, StubInformation> stubs = new HashMap<>(); 283 284 /** 285 * List of referenced classes. 286 */ 287 private Map<String, AOTKlassData> dependentKlasses = new HashMap<>(); 288 289 /** 290 * Methods count used to generate unique global method id. 291 */ 292 private static final AtomicInteger methodsCount = new AtomicInteger(); 293 294 public CompiledMethodInfo(CompilationResult compilationResult, JavaMethodInfo methodInfo) { 295 this.name = methodInfo.getNameAndSignature(); 296 this.compilationResult = compilationResult; 297 this.methodInfo = methodInfo; 298 this.stubsOffset = UNINITIALIZED_OFFSET; 299 this.methodOffsets = new AOTMethodOffsets(); 300 } 301 302 public String name() { 303 return name; 304 } 305 306 public void addMethodOffsets(BinaryContainer binaryContainer, ReadOnlyDataContainer container) { 307 this.methodOffsets.setNameOffset(binaryContainer.addMetaspaceName(name)); 308 this.methodOffsets.addMethodOffsets(container, name); 309 for (AOTKlassData data : dependentKlasses.values()) { 310 data.addDependentMethod(this); 311 } 312 } 313 314 public CompilationResult getCompilationResult() { 315 return compilationResult; 316 } 317 318 public JavaMethodInfo getMethodInfo() { 319 return methodInfo; 320 } 321 322 public void setTextSectionOffset(int textSectionOffset) { 323 methodOffsets.setTextSectionOffset(textSectionOffset); 324 } 325 326 public int getTextSectionOffset() { 327 return methodOffsets.getTextSectionOffset(); 328 } 329 330 public void setCodeId() { 331 methodOffsets.setCodeId(CompiledMethodInfo.getNextCodeId()); 332 } 333 334 public int getCodeId() { 335 return this.methodOffsets.getCodeId(); 336 } 337 338 public static int getMethodsCount() { 339 return methodsCount.get(); 340 } 341 342 public static int getNextCodeId() { 343 return methodsCount.getAndIncrement(); 344 } 345 346 public int getCodeSize() { 347 return stubsOffset + getStubCodeSize(); 348 } 349 350 public int getStubCodeSize() { 351 return totalStubSize; 352 } 353 354 public void setMetadataOffset(int offset) { 355 this.methodOffsets.setMetadataOffset(offset); 356 } 357 358 /** 359 * Offset into the code of this method where the stub section starts. 360 */ 361 public void setStubsOffset(int offset) { 362 stubsOffset = offset; 363 } 364 365 public int getStubsOffset() { 366 return stubsOffset; 367 } 368 369 public void setMetadataGotOffset(int metadataGotOffset) { 370 this.methodOffsets.setMetadataGotOffset(metadataGotOffset); 371 } 372 373 public void setMetadataGotSize(int length) { 374 this.methodOffsets.setMetadataGotSize(length); 375 } 376 377 public void addStubCode(String call, StubInformation stub) { 378 stubs.put(call, stub); 379 totalStubSize += stub.getSize(); 380 } 381 382 public StubInformation getStubFor(String call) { 383 StubInformation stub = stubs.get(call); 384 assert stub != null : "missing stub for call " + call; 385 stub.verify(); 386 return stub; 387 } 388 389 public void addDependentKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) { 390 AOTKlassData klassData = AOTCompiledClass.addFingerprintKlassData(binaryContainer, type); 391 String klassName = type.getName(); 392 393 if (dependentKlasses.containsKey(klassName)) { 394 assert dependentKlasses.get(klassName) == klassData : "duplicated data for klass: " + klassName; 395 } else { 396 dependentKlasses.put(klassName, klassData); 397 } 398 } 399 400 public AOTKlassData getDependentKlassData(String klassName) { 401 return dependentKlasses.get(klassName); 402 } 403 404 public boolean hasMark(Site call, MarkId id) { 405 for (Mark m : compilationResult.getMarks()) { 406 // TODO: X64-specific code. 407 // Call instructions are aligned to 8 408 // bytes - 1 on x86 to patch address atomically, 409 int adjOffset = (m.pcOffset & (-8)) + 7; 410 // Mark points before aligning nops. 411 if ((call.pcOffset == adjOffset) && MarkId.getEnum((int) m.id) == id) { 412 return true; 413 } 414 } 415 return false; 416 } 417 418 public String asTag() { 419 return "[" + methodInfo.getSymbolName() + "]"; 420 } 421 422 public HotSpotCompiledCode compiledCode() { 423 if (code == null) { 424 code = methodInfo.compiledCode(compilationResult); 425 } 426 return code; 427 } 428 429 // Free memory 430 public void clear() { 431 this.dependentKlasses = null; 432 this.name = null; 433 } 434 435 public void clearCompileData() { 436 this.code = null; 437 this.stubs = null; 438 this.compilationResult = null; 439 this.methodInfo = null; 440 } 441 } | 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.Map; 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 177 /** 178 * Method's offsets. 179 */ 180 private AOTMethodOffsets methodOffsets; 181 182 /** 183 * List of stubs (PLT trampoline). 184 */ 185 private Map<String, StubInformation> stubs = new HashMap<>(); 186 187 /** 188 * List of referenced classes. 189 */ 190 private Map<String, AOTKlassData> dependentKlasses = new HashMap<>(); 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.values()) { 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 String klassName = type.getName(); 295 296 if (dependentKlasses.containsKey(klassName)) { 297 assert dependentKlasses.get(klassName) == klassData : "duplicated data for klass: " + klassName; 298 } else { 299 dependentKlasses.put(klassName, klassData); 300 } 301 } 302 303 AOTKlassData getDependentKlassData(String klassName) { 304 return dependentKlasses.get(klassName); 305 } 306 307 boolean hasMark(Site call, MarkId id) { 308 for (Mark m : compilationResult.getMarks()) { 309 // TODO: X64-specific code. 310 // Call instructions are aligned to 8 311 // bytes - 1 on x86 to patch address atomically, 312 int adjOffset = (m.pcOffset & (-8)) + 7; 313 // Mark points before aligning nops. 314 if ((call.pcOffset == adjOffset) && MarkId.getEnum((int) m.id) == id) { 315 return true; 316 } 317 } 318 return false; 319 } 320 321 String asTag() { 322 return "[" + methodInfo.getSymbolName() + "]"; 323 } 324 325 HotSpotCompiledCode compiledCode() { 326 if (code == null) { 327 code = methodInfo.compiledCode(compilationResult); 328 } 329 return code; 330 } 331 332 // Free memory 333 void clear() { 334 this.dependentKlasses = null; 335 this.name = null; 336 } 337 338 void clearCompileData() { 339 this.code = null; 340 this.stubs = null; 341 this.compilationResult = null; 342 this.methodInfo = null; 343 } 344 } |