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 }