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