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.ArrayList; 27 import java.util.HashMap; 28 import java.util.List; 29 import java.util.Map.Entry; 30 31 import jdk.tools.jaotc.binformat.BinaryContainer; 32 import jdk.tools.jaotc.binformat.ByteContainer; 33 import jdk.tools.jaotc.binformat.HeaderContainer; 34 import jdk.tools.jaotc.utils.Timer; 35 import org.graalvm.compiler.code.CompilationResult; 36 import org.graalvm.compiler.debug.Debug; 37 import org.graalvm.compiler.debug.Debug.Scope; 38 import org.graalvm.compiler.hotspot.HotSpotHostBackend; 39 import org.graalvm.compiler.hotspot.stubs.Stub; 40 41 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; 42 import jdk.vm.ci.hotspot.HotSpotVMConfigStore; 43 import jdk.vm.ci.hotspot.VMField; 44 45 class DataBuilder { 46 47 private final Main main; 48 49 private final HotSpotHostBackend backend; 50 51 private final List<AOTCompiledClass> classes; 52 53 /** 54 * Target-independent container in which text symbols and code bytes are created. 55 */ 56 private final BinaryContainer binaryContainer; 57 58 private final HashMap<Long, String> vmAddresses = new HashMap<>(); 59 60 public DataBuilder(Main main, HotSpotHostBackend backend, List<AOTCompiledClass> classes, BinaryContainer binaryContainer) { 61 this.main = main; 62 this.backend = backend; 63 this.classes = classes; 64 this.binaryContainer = binaryContainer; 65 fillVMAddresses(HotSpotJVMCIRuntime.runtime().getConfigStore()); 66 } 67 68 /** 69 * Returns a value-name map of all {@link VMField} fields. 70 */ 71 private void fillVMAddresses(HotSpotVMConfigStore config) { 72 for (VMField vmField : config.getFields().values()) { 73 if (vmField.value != null) { 74 final long address = vmField.value; 75 String value = vmField.name; 76 /* 77 * Some fields don't contain addresses but integer values. At least don't add zero 78 * entries to avoid matching null addresses. 79 */ 80 if (address != 0) { 81 vmAddresses.put(address, value); 82 } 83 } 84 } 85 for (Entry<String, Long> vmAddress : config.getAddresses().entrySet()) { 86 final long address = vmAddress.getValue(); 87 String value = vmAddress.getKey(); 88 String old = vmAddresses.put(address, value); 89 if (old != null) { 90 throw new InternalError("already in map: address: " + address + ", current: " + value + ", old: " + old); 91 } 92 } 93 } 94 95 /** 96 * Get the C/C++ function name associated with the foreign call target {@code address}. 97 * 98 * @param address native address 99 * @return C/C++ functio name associated with the native address 100 */ 101 public String getVMFunctionNameForAddress(long address) { 102 return vmAddresses.get(address); 103 } 104 105 /** 106 * Returns the host backend used for this compilation. 107 * 108 * @return host backend 109 */ 110 public HotSpotHostBackend getBackend() { 111 return backend; 112 } 113 114 /** 115 * Returns the binary container for this compilation. 116 * 117 * @return binary container 118 */ 119 public BinaryContainer getBinaryContainer() { 120 return binaryContainer; 121 } 122 123 /** 124 * Prepare data with all compiled classes and stubs. 125 * 126 * @throws Exception 127 */ 128 @SuppressWarnings("try") 129 public void prepareData() throws Exception { 130 try (Timer t = new Timer(main, "Parsing compiled code")) { 131 /* 132 * Copy compiled code into code section container and calls stubs (PLT trampoline). 133 */ 134 CodeSectionProcessor codeSectionProcessor = new CodeSectionProcessor(this); 135 for (AOTCompiledClass c : classes) { 136 // For each class we need 2 GOT slots: 137 // first - for initialized klass 138 // second - only for loaded klass 139 c.addAOTKlassData(binaryContainer); 140 codeSectionProcessor.process(c); 141 } 142 } 143 144 AOTCompiledClass stubCompiledCode = retrieveStubCode(); 145 146 // Free memory! 147 try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) { 148 main.printMemoryUsage(); 149 System.gc(); 150 } 151 152 MetadataBuilder metadataBuilder = null; 153 try (Timer t = new Timer(main, "Processing metadata")) { 154 /* 155 * Generate metadata for compiled code and copy it into metadata section. Create 156 * relocation information for all references (call, constants, etc) in compiled code. 157 */ 158 metadataBuilder = new MetadataBuilder(this); 159 metadataBuilder.processMetadata(classes, stubCompiledCode); 160 } 161 162 // Free memory! 163 try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) { 164 main.printMemoryUsage(); 165 System.gc(); 166 } 167 168 try (Timer t = new Timer(main, "Preparing stubs binary")) { 169 prepareStubsBinary(stubCompiledCode); 170 } 171 try (Timer t = new Timer(main, "Preparing compiled binary")) { 172 // Should be called after Stubs because they can set dependent klasses. 173 prepareCompiledBinary(metadataBuilder); 174 } 175 } 176 177 /** 178 * Get all stubs from Graal and add them to the code section. 179 */ 180 @SuppressWarnings("try") 181 private AOTCompiledClass retrieveStubCode() { 182 ArrayList<CompiledMethodInfo> stubs = new ArrayList<>(); 183 for (Stub stub : Stub.getStubs()) { 184 try (Scope scope = Debug.scope("CompileStubs")) { 185 CompilationResult result = stub.getCompilationResult(backend); 186 CompiledMethodInfo cm = new CompiledMethodInfo(result, new AOTStub(stub, backend)); 187 stubs.add(cm); 188 } catch (Throwable e) { 189 throw Debug.handle(e); 190 } 191 } 192 AOTCompiledClass stubCompiledCode = new AOTCompiledClass(stubs); 193 CodeSectionProcessor codeSectionProcessor = new CodeSectionProcessor(this); 194 codeSectionProcessor.process(stubCompiledCode); 195 return stubCompiledCode; 196 } 197 198 /** 199 * Prepare metaspace.offsets section. 200 */ 201 private void prepareCompiledBinary(MetadataBuilder metadataBuilder) { 202 for (AOTCompiledClass c : classes) { 203 // Create records for compiled AOT methods. 204 c.putMethodsData(binaryContainer); 205 } 206 // Create records for compiled AOT classes. 207 AOTCompiledClass.putAOTKlassData(binaryContainer); 208 209 // Fill in AOTHeader 210 HeaderContainer header = binaryContainer.getHeaderContainer(); 211 header.setClassesCount(AOTCompiledClass.getClassesCount()); 212 header.setMethodsCount(CompiledMethodInfo.getMethodsCount()); 213 // Record size of got sections 214 ByteContainer bc = binaryContainer.getMetaspaceGotContainer(); 215 header.setMetaspaceGotSize((bc.getByteStreamSize() / 8)); 216 bc = binaryContainer.getMetadataGotContainer(); 217 header.setMetadataGotSize((bc.getByteStreamSize() / 8)); 218 bc = binaryContainer.getOopGotContainer(); 219 header.setOopGotSize((bc.getByteStreamSize() / 8)); 220 } 221 222 /** 223 * Prepare stubs.offsets section. 224 */ 225 private void prepareStubsBinary(AOTCompiledClass compiledClass) { 226 // For each of the compiled stubs, create records holding information about 227 // them. 228 ArrayList<CompiledMethodInfo> compiledStubs = compiledClass.getCompiledMethods(); 229 int cntStubs = compiledStubs.size(); 230 binaryContainer.addMethodsCount(cntStubs, binaryContainer.getStubsOffsetsContainer()); 231 for (CompiledMethodInfo methodInfo : compiledStubs) { 232 // Note, stubs have different offsets container. 233 methodInfo.addMethodOffsets(binaryContainer, binaryContainer.getStubsOffsetsContainer()); 234 } 235 } 236 237 }