1 /* 2 * Copyright (c) 2016, 2018, 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 25 26 package jdk.tools.jaotc; 27 28 import java.util.ArrayList; 29 import java.util.HashMap; 30 import java.util.List; 31 import java.util.Map.Entry; 32 33 import org.graalvm.compiler.code.CompilationResult; 34 import org.graalvm.compiler.debug.DebugContext; 35 import org.graalvm.compiler.hotspot.HotSpotHostBackend; 36 import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; 37 import org.graalvm.compiler.hotspot.stubs.Stub; 38 39 import jdk.tools.jaotc.binformat.BinaryContainer; 40 import jdk.tools.jaotc.binformat.ByteContainer; 41 import jdk.tools.jaotc.binformat.HeaderContainer; 42 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; 43 import jdk.vm.ci.hotspot.HotSpotVMConfigStore; 44 import jdk.vm.ci.hotspot.VMField; 45 46 final 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 static final HashMap<Long, String> vmAddresses = new HashMap<>(); 60 61 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 static 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 static 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 HotSpotHostBackend getBackend() { 112 return backend; 113 } 114 115 /** 116 * Returns the binary container for this compilation. 117 * 118 * @return binary container 119 */ 120 BinaryContainer getBinaryContainer() { 121 return binaryContainer; 122 } 123 124 /** 125 * Prepare data with all compiled classes and stubs. 126 * 127 * @param debug 128 * 129 * @throws Exception 130 */ 131 @SuppressWarnings("try") 132 void prepareData(DebugContext debug) throws Exception { 133 try (Timer t = new Timer(main, "Parsing compiled code")) { 134 /* 135 * Copy compiled code into code section container and calls stubs (PLT trampoline). 136 */ 137 CodeSectionProcessor codeSectionProcessor = new CodeSectionProcessor(this); 138 for (AOTCompiledClass c : classes) { 139 // For each class we need 2 GOT slots: 140 // first - for initialized klass 141 // second - only for loaded klass 142 c.addAOTKlassData(binaryContainer); 143 codeSectionProcessor.process(c); 144 } 145 } 146 147 AOTCompiledClass stubCompiledCode = retrieveStubCode(debug); 148 149 // Free memory! 150 try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) { 151 main.printer.printMemoryUsage(); 152 System.gc(); 153 } 154 155 MetadataBuilder metadataBuilder = null; 156 try (Timer t = new Timer(main, "Processing metadata")) { 157 /* 158 * Generate metadata for compiled code and copy it into metadata section. Create 159 * relocation information for all references (call, constants, etc) in compiled code. 160 */ 161 metadataBuilder = new MetadataBuilder(this); 162 metadataBuilder.processMetadata(classes, stubCompiledCode); 163 } 164 165 // Free memory! 166 try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) { 167 main.printer.printMemoryUsage(); 168 System.gc(); 169 } 170 171 try (Timer t = new Timer(main, "Preparing stubs binary")) { 172 prepareStubsBinary(stubCompiledCode); 173 } 174 try (Timer t = new Timer(main, "Preparing compiled binary")) { 175 // Should be called after Stubs because they can set dependent klasses. 176 prepareCompiledBinary(); 177 } 178 } 179 180 /** 181 * Get all stubs from Graal and add them to the code section. 182 * 183 * @param debug 184 */ 185 @SuppressWarnings("try") 186 private AOTCompiledClass retrieveStubCode(DebugContext debug) { 187 ArrayList<CompiledMethodInfo> stubs = new ArrayList<>(); 188 HotSpotForeignCallsProvider foreignCallsProvider = backend.getProviders().getForeignCalls(); 189 for (Stub stub : foreignCallsProvider.getStubs()) { 190 try (DebugContext.Scope scope = debug.scope("CompileStubs")) { 191 CompilationResult result = stub.getCompilationResult(debug, backend); 192 CompiledMethodInfo cm = new CompiledMethodInfo(result, new AOTStub(stub, backend, debug.getOptions())); 193 stubs.add(cm); 194 } catch (Throwable e) { 195 throw debug.handle(e); 196 } 197 } 198 AOTCompiledClass stubCompiledCode = new AOTCompiledClass(stubs); 199 CodeSectionProcessor codeSectionProcessor = new CodeSectionProcessor(this); 200 codeSectionProcessor.process(stubCompiledCode); 201 return stubCompiledCode; 202 } 203 204 /** 205 * Prepare metaspace.offsets section. 206 */ 207 private void prepareCompiledBinary() { 208 for (AOTCompiledClass c : classes) { 209 // Create records for compiled AOT methods. 210 c.putMethodsData(binaryContainer); 211 } 212 // Create records for compiled AOT classes. 213 AOTCompiledClass.putAOTKlassData(binaryContainer); 214 215 // Fill in AOTHeader 216 HeaderContainer header = binaryContainer.getHeaderContainer(); 217 header.setClassesCount(AOTCompiledClass.getClassesCount()); 218 header.setMethodsCount(CompiledMethodInfo.getMethodsCount()); 219 // Record size of got sections 220 ByteContainer bc = binaryContainer.getKlassesGotContainer(); 221 header.setKlassesGotSize((bc.getByteStreamSize() / 8)); 222 bc = binaryContainer.getMetadataGotContainer(); 223 header.setMetadataGotSize((bc.getByteStreamSize() / 8)); 224 bc = binaryContainer.getOopGotContainer(); 225 header.setOopGotSize((bc.getByteStreamSize() / 8)); 226 } 227 228 /** 229 * Prepare stubs.offsets section. 230 */ 231 private void prepareStubsBinary(AOTCompiledClass compiledClass) { 232 // For each of the compiled stubs, create records holding information about 233 // them. 234 ArrayList<CompiledMethodInfo> compiledStubs = compiledClass.getCompiledMethods(); 235 int cntStubs = compiledStubs.size(); 236 BinaryContainer.addMethodsCount(cntStubs, binaryContainer.getStubsOffsetsContainer()); 237 for (CompiledMethodInfo methodInfo : compiledStubs) { 238 // Note, stubs have different offsets container. 239 methodInfo.addMethodOffsets(binaryContainer, binaryContainer.getStubsOffsetsContainer()); 240 } 241 } 242 243 }