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