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 }