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.binformat; 25 26 import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT; 27 28 import java.io.ByteArrayOutputStream; 29 import java.io.DataOutputStream; 30 import java.io.IOException; 31 import java.util.ArrayList; 32 import java.util.HashMap; 33 import java.util.List; 34 import java.util.Map; 35 36 import jdk.tools.jaotc.binformat.Symbol.Binding; 37 import jdk.tools.jaotc.binformat.Symbol.Kind; 38 import jdk.tools.jaotc.binformat.elf.JELFRelocObject; 39 import jdk.tools.jaotc.binformat.macho.JMachORelocObject; 40 import jdk.tools.jaotc.binformat.pecoff.JPECoffRelocObject; 41 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; 42 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; 43 44 /** 45 * A format-agnostic container class that holds various components of a binary. 46 * 47 * <p> 48 * This class holds information necessary to create platform-specific binary containers such as 49 * ELFContainer for Linux and Solaris operating systems or MachOContainer for Mac 50 * OS or PEContainer for MS Windows operating systems. 51 * 52 * <p> 53 * Method APIs provided by this class are used to construct and populate platform-independent 54 * contents of a binary as the first step to create a binary representation of code generated by a 55 * compiler backend such as Graal. 56 * 57 * <p> 58 * Methods to record and access code section contents, symbols and relocations are provided. 59 */ 60 public class BinaryContainer implements SymbolTable { 61 62 private final int codeSegmentSize; 63 64 private final int codeEntryAlignment; 65 66 /** 67 * Container holding code bits and any other related information. 68 */ 69 private final CodeContainer codeContainer; 70 71 /** 72 * Container holding external hotspot linkage bits (PLT entries). 73 */ 74 private final CodeContainer extLinkageContainer; 75 76 /** 77 * Container holding global offset data for hotspot linkage. 78 */ 79 private final ByteContainer extLinkageGOTContainer; 80 81 /** 82 * Patched by HotSpot, contains metaspace pointers. 83 */ 84 private final ByteContainer metaspaceGotContainer; 85 86 /** 87 * Patched lazily by hotspot, contains klass/method pointers. 88 */ 89 private final ByteContainer metadataGotContainer; 90 91 /** 92 * BSS container, contains method state array. 93 */ 94 private final ByteContainer methodStateContainer; 95 96 /** 97 * Patched by hotspot, contains java object pointers. 98 */ 99 private final ByteContainer oopGotContainer; 100 101 // Containers holding read-only data 102 private final ReadOnlyDataContainer configContainer; 103 private final ReadOnlyDataContainer metaspaceNamesContainer; 104 private final ReadOnlyDataContainer methodsOffsetsContainer; 105 private final ReadOnlyDataContainer klassesOffsetsContainer; 106 private final ReadOnlyDataContainer klassesDependenciesContainer; 107 private final HeaderContainer headerContainer; 108 private final ReadOnlyDataContainer stubsOffsetsContainer; 109 private final ReadOnlyDataContainer codeSegmentsContainer; 110 111 // This cannot be read only since we need to patch the metadata at runtime.. 112 private final ReadOnlyDataContainer methodMetadataContainer; 113 114 /** 115 * Container containing constant data used by code. 116 */ 117 private final ReadOnlyDataContainer constantDataContainer; 118 119 /** 120 * Map holding the Strings table. 121 */ 122 private final Map<String, Integer> offsetStringTable = new HashMap<>(); 123 124 private final Map<String, Integer> metaspaceNames = new HashMap<>(); 125 126 // List of relocation table entries - (symbolName, relocationInfo) 127 private final Map<String, Symbol> symbolTable = new HashMap<>(); 128 private final Map<Symbol, List<Relocation>> relocationTable = new HashMap<>(); 129 private final Map<Symbol, Relocation> uniqueRelocationTable = new HashMap<>(); 130 131 /** 132 * Mapping of local VM function names to known global symbols generated in the output binary. 133 */ 134 private static final HashMap<String, String> functionNamesToAOTSymbols = new HashMap<>(); 135 136 private static final String[][] map = { 137 //@formatter:off 138 {"CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", "_aot_deopt_blob_unpack"}, 139 {"CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap", "_aot_deopt_blob_uncommon_trap"}, 140 {"CompilerToVM::Data::SharedRuntime_ic_miss_stub", "_aot_ic_miss_stub"}, 141 {"CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub", "_aot_handle_wrong_method_stub"}, 142 {"SharedRuntime::exception_handler_for_return_address", "_aot_exception_handler_for_return_address"}, 143 {"SharedRuntime::register_finalizer", "_aot_register_finalizer"}, 144 {"SharedRuntime::OSR_migration_end", "_aot_OSR_migration_end"}, 145 {"CompilerRuntime::resolve_string_by_symbol", "_aot_resolve_string_by_symbol"}, 146 {"CompilerRuntime::resolve_klass_by_symbol", "_aot_resolve_klass_by_symbol"}, 147 {"CompilerRuntime::resolve_method_by_symbol_and_load_counters","_aot_resolve_method_by_symbol_and_load_counters"}, 148 {"CompilerRuntime::initialize_klass_by_symbol", "_aot_initialize_klass_by_symbol"}, 149 {"CompilerRuntime::invocation_event", "_aot_invocation_event"}, 150 {"CompilerRuntime::backedge_event", "_aot_backedge_event"}, 151 152 {"CompilerToVM::Data::dpow", "_aot_shared_runtime_dpow"}, 153 {"CompilerToVM::Data::dexp", "_aot_shared_runtime_dexp"}, 154 {"CompilerToVM::Data::dcos", "_aot_shared_runtime_dcos"}, 155 {"CompilerToVM::Data::dsin", "_aot_shared_runtime_dsin"}, 156 {"CompilerToVM::Data::dtan", "_aot_shared_runtime_dtan"}, 157 {"CompilerToVM::Data::dlog", "_aot_shared_runtime_dlog"}, 158 {"CompilerToVM::Data::dlog10", "_aot_shared_runtime_dlog10"}, 159 160 {"StubRoutines::_jbyte_arraycopy", "_aot_stub_routines_jbyte_arraycopy"}, 161 {"StubRoutines::_jshort_arraycopy", "_aot_stub_routines_jshort_arraycopy"}, 162 {"StubRoutines::_jint_arraycopy", "_aot_stub_routines_jint_arraycopy"}, 163 {"StubRoutines::_jlong_arraycopy", "_aot_stub_routines_jlong_arraycopy"}, 164 {"StubRoutines::_oop_arraycopy", "_aot_stub_routines_oop_arraycopy"}, 165 {"StubRoutines::_oop_arraycopy_uninit", "_aot_stub_routines_oop_arraycopy_uninit"}, 166 167 {"StubRoutines::_jbyte_disjoint_arraycopy", "_aot_stub_routines_jbyte_disjoint_arraycopy"}, 168 {"StubRoutines::_jshort_disjoint_arraycopy", "_aot_stub_routines_jshort_disjoint_arraycopy"}, 169 {"StubRoutines::_jint_disjoint_arraycopy", "_aot_stub_routines_jint_disjoint_arraycopy"}, 170 {"StubRoutines::_jlong_disjoint_arraycopy", "_aot_stub_routines_jlong_disjoint_arraycopy"}, 171 {"StubRoutines::_oop_disjoint_arraycopy", "_aot_stub_routines_oop_disjoint_arraycopy"}, 172 {"StubRoutines::_oop_disjoint_arraycopy_uninit", "_aot_stub_routines_oop_disjoint_arraycopy_uninit"}, 173 174 {"StubRoutines::_arrayof_jbyte_arraycopy", "_aot_stub_routines_arrayof_jbyte_arraycopy"}, 175 {"StubRoutines::_arrayof_jshort_arraycopy", "_aot_stub_routines_arrayof_jshort_arraycopy"}, 176 {"StubRoutines::_arrayof_jint_arraycopy", "_aot_stub_routines_arrayof_jint_arraycopy"}, 177 {"StubRoutines::_arrayof_jlong_arraycopy", "_aot_stub_routines_arrayof_jlong_arraycopy"}, 178 {"StubRoutines::_arrayof_oop_arraycopy", "_aot_stub_routines_arrayof_oop_arraycopy"}, 179 {"StubRoutines::_arrayof_oop_arraycopy_uninit", "_aot_stub_routines_arrayof_oop_arraycopy_uninit"}, 180 181 {"StubRoutines::_arrayof_jbyte_disjoint_arraycopy", "_aot_stub_routines_arrayof_jbyte_disjoint_arraycopy"}, 182 {"StubRoutines::_arrayof_jshort_disjoint_arraycopy", "_aot_stub_routines_arrayof_jshort_disjoint_arraycopy"}, 183 {"StubRoutines::_arrayof_jint_disjoint_arraycopy", "_aot_stub_routines_arrayof_jint_disjoint_arraycopy"}, 184 {"StubRoutines::_arrayof_jlong_disjoint_arraycopy", "_aot_stub_routines_arrayof_jlong_disjoint_arraycopy"}, 185 {"StubRoutines::_arrayof_oop_disjoint_arraycopy", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy"}, 186 {"StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit"}, 187 188 {"StubRoutines::_checkcast_arraycopy", "_aot_stub_routines_checkcast_arraycopy"}, 189 190 191 192 193 {"StubRoutines::_aescrypt_encryptBlock", "_aot_stub_routines_aescrypt_encryptBlock"}, 194 {"StubRoutines::_aescrypt_decryptBlock", "_aot_stub_routines_aescrypt_decryptBlock"}, 195 {"StubRoutines::_cipherBlockChaining_encryptAESCrypt", "_aot_stub_routines_cipherBlockChaining_encryptAESCrypt"}, 196 {"StubRoutines::_cipherBlockChaining_decryptAESCrypt", "_aot_stub_routines_cipherBlockChaining_decryptAESCrypt"}, 197 {"StubRoutines::_updateBytesCRC32", "_aot_stub_routines_update_bytes_crc32"}, 198 {"StubRoutines::_crc_table_adr", "_aot_stub_routines_crc_table_adr"}, 199 200 {"StubRoutines::_sha1_implCompress", "_aot_stub_routines_sha1_implCompress" }, 201 {"StubRoutines::_sha1_implCompressMB", "_aot_stub_routines_sha1_implCompressMB" }, 202 {"StubRoutines::_sha256_implCompress", "_aot_stub_routines_sha256_implCompress" }, 203 {"StubRoutines::_sha256_implCompressMB", "_aot_stub_routines_sha256_implCompressMB" }, 204 {"StubRoutines::_sha512_implCompress", "_aot_stub_routines_sha512_implCompress" }, 205 {"StubRoutines::_sha512_implCompressMB", "_aot_stub_routines_sha512_implCompressMB" }, 206 {"StubRoutines::_multiplyToLen", "_aot_stub_routines_multiplyToLen" }, 207 208 {"StubRoutines::_counterMode_AESCrypt", "_aot_stub_routines_counterMode_AESCrypt" }, 209 {"StubRoutines::_ghash_processBlocks", "_aot_stub_routines_ghash_processBlocks" }, 210 {"StubRoutines::_crc32c_table_addr", "_aot_stub_routines_crc32c_table_addr" }, 211 {"StubRoutines::_updateBytesCRC32C", "_aot_stub_routines_updateBytesCRC32C" }, 212 {"StubRoutines::_updateBytesAdler32", "_aot_stub_routines_updateBytesAdler32" }, 213 {"StubRoutines::_squareToLen", "_aot_stub_routines_squareToLen" }, 214 {"StubRoutines::_mulAdd", "_aot_stub_routines_mulAdd" }, 215 {"StubRoutines::_montgomeryMultiply", "_aot_stub_routines_montgomeryMultiply" }, 216 {"StubRoutines::_montgomerySquare", "_aot_stub_routines_montgomerySquare" }, 217 {"StubRoutines::_vectorizedMismatch", "_aot_stub_routines_vectorizedMismatch" }, 218 219 {"StubRoutines::_throw_delayed_StackOverflowError_entry", "_aot_stub_routines_throw_delayed_StackOverflowError_entry" }, 220 221 222 {"os::javaTimeMillis", "_aot_os_javaTimeMillis"}, 223 {"os::javaTimeNanos", "_aot_os_javaTimeNanos"}, 224 225 {"JVMCIRuntime::monitorenter", "_aot_jvmci_runtime_monitorenter"}, 226 {"JVMCIRuntime::monitorexit", "_aot_jvmci_runtime_monitorexit"}, 227 {"JVMCIRuntime::log_object", "_aot_jvmci_runtime_log_object"}, 228 {"JVMCIRuntime::log_printf", "_aot_jvmci_runtime_log_printf"}, 229 {"JVMCIRuntime::vm_message", "_aot_jvmci_runtime_vm_message"}, 230 {"JVMCIRuntime::new_instance", "_aot_jvmci_runtime_new_instance"}, 231 {"JVMCIRuntime::log_primitive", "_aot_jvmci_runtime_log_primitive"}, 232 {"JVMCIRuntime::new_multi_array", "_aot_jvmci_runtime_new_multi_array"}, 233 {"JVMCIRuntime::validate_object", "_aot_jvmci_runtime_validate_object"}, 234 {"JVMCIRuntime::dynamic_new_array", "_aot_jvmci_runtime_dynamic_new_array"}, 235 {"JVMCIRuntime::write_barrier_pre", "_aot_jvmci_runtime_write_barrier_pre"}, 236 {"JVMCIRuntime::identity_hash_code", "_aot_jvmci_runtime_identity_hash_code"}, 237 {"JVMCIRuntime::write_barrier_post", "_aot_jvmci_runtime_write_barrier_post"}, 238 {"JVMCIRuntime::dynamic_new_instance", "_aot_jvmci_runtime_dynamic_new_instance"}, 239 {"JVMCIRuntime::thread_is_interrupted", "_aot_jvmci_runtime_thread_is_interrupted"}, 240 {"JVMCIRuntime::exception_handler_for_pc", "_aot_jvmci_runtime_exception_handler_for_pc"}, 241 {"JVMCIRuntime::test_deoptimize_call_int", "_aot_jvmci_runtime_test_deoptimize_call_int"}, 242 243 {"JVMCIRuntime::throw_and_post_jvmti_exception", "_aot_jvmci_runtime_throw_and_post_jvmti_exception"}, 244 {"JVMCIRuntime::throw_klass_external_name_exception", "_aot_jvmci_runtime_throw_klass_external_name_exception"}, 245 {"JVMCIRuntime::throw_class_cast_exception", "_aot_jvmci_runtime_throw_class_cast_exception"}, 246 247 {"JVMCIRuntime::vm_error", "_aot_jvmci_runtime_vm_error"}, 248 {"JVMCIRuntime::new_array", "_aot_jvmci_runtime_new_array"} 249 //@formatter:on 250 }; 251 252 static { 253 for (String[] entry : map) { 254 functionNamesToAOTSymbols.put(entry[0], entry[1]); 255 } 256 } 257 258 /** 259 * Allocates a {@code BinaryContainer} object whose content will be generated in a file with the 260 * prefix {@code prefix}. It also initializes internal code container, symbol table and 261 * relocation tables. 262 */ 263 public BinaryContainer(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, String jvmVersion) { 264 this.codeSegmentSize = graalHotSpotVMConfig.codeSegmentSize; 265 this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment; 266 267 // read only, code 268 codeContainer = new CodeContainer(".text", this); 269 extLinkageContainer = new CodeContainer(".hs.plt.linkage", this); 270 271 // read only, info 272 configContainer = new ReadOnlyDataContainer(".config", this); 273 metaspaceNamesContainer = new ReadOnlyDataContainer(".meta.names", this); 274 methodsOffsetsContainer = new ReadOnlyDataContainer(".methods.offsets", this); 275 klassesOffsetsContainer = new ReadOnlyDataContainer(".kls.offsets", this); 276 klassesDependenciesContainer = new ReadOnlyDataContainer(".kls.dependencies", this); 277 278 headerContainer = new HeaderContainer(jvmVersion, new ReadOnlyDataContainer(".header", this)); 279 stubsOffsetsContainer = new ReadOnlyDataContainer(".stubs.offsets", this); 280 codeSegmentsContainer = new ReadOnlyDataContainer(".code.segments", this); 281 constantDataContainer = new ReadOnlyDataContainer(".meth.constdata", this); 282 283 // needs relocation patching at load time by the loader 284 methodMetadataContainer = new ReadOnlyDataContainer(".meth.metadata", this); 285 286 // writable sections 287 metaspaceGotContainer = new ByteContainer(".meta.got", this); 288 metadataGotContainer = new ByteContainer(".metadata.got", this); 289 methodStateContainer = new ByteContainer(".meth.state", this); 290 oopGotContainer = new ByteContainer(".oop.got", this); 291 extLinkageGOTContainer = new ByteContainer(".hs.got.linkage", this); 292 293 addGlobalSymbols(); 294 295 recordConfiguration(graalHotSpotVMConfig, graphBuilderConfig); 296 } 297 298 private void recordConfiguration(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig) { 299 // @formatter:off 300 boolean[] booleanFlags = { graalHotSpotVMConfig.cAssertions, // Debug VM 301 graalHotSpotVMConfig.useCompressedOops, 302 graalHotSpotVMConfig.useCompressedClassPointers, 303 graalHotSpotVMConfig.compactFields, 304 graalHotSpotVMConfig.useG1GC, 305 graalHotSpotVMConfig.useCMSGC, 306 graalHotSpotVMConfig.useTLAB, 307 graalHotSpotVMConfig.useBiasedLocking, 308 TieredAOT.getValue(), 309 graalHotSpotVMConfig.enableContended, 310 graalHotSpotVMConfig.restrictContended, 311 graphBuilderConfig.omitAssertions() 312 }; 313 314 int[] intFlags = { graalHotSpotVMConfig.getOopEncoding().shift, 315 graalHotSpotVMConfig.getKlassEncoding().shift, 316 graalHotSpotVMConfig.contendedPaddingWidth, 317 graalHotSpotVMConfig.fieldsAllocationStyle, 318 1 << graalHotSpotVMConfig.getOopEncoding().alignment, 319 graalHotSpotVMConfig.codeSegmentSize, 320 }; 321 // @formatter:on 322 323 byte[] booleanFlagsAsBytes = flagsToByteArray(booleanFlags); 324 int size0 = configContainer.getByteStreamSize(); 325 326 // @formatter:off 327 int computedSize = booleanFlagsAsBytes.length * Byte.BYTES + // size of boolean flags 328 intFlags.length * Integer.BYTES + // size of int flags 329 Integer.BYTES; // size of the "computedSize" 330 331 configContainer.appendInt(computedSize). 332 appendInts(intFlags). 333 appendBytes(booleanFlagsAsBytes); 334 // @formatter:on 335 336 int size = configContainer.getByteStreamSize() - size0; 337 assert size == computedSize; 338 } 339 340 private static byte[] flagsToByteArray(boolean[] flags) { 341 byte[] byteArray = new byte[flags.length]; 342 for (int i = 0; i < flags.length; ++i) { 343 byteArray[i] = boolToByte(flags[i]); 344 } 345 return byteArray; 346 } 347 348 private static byte boolToByte(boolean flag) { 349 return (byte) (flag ? 1 : 0); 350 } 351 352 /** 353 * Free some memory. 354 */ 355 public void freeMemory() { 356 offsetStringTable.clear(); 357 metaspaceNames.clear(); 358 } 359 360 /* 361 * Global symbol names in generated DSO corresponding to VM's symbols. VM needs to look up this 362 * symbol in DSO and link it with VM's corresponding symbol: store VM's symbol address or value 363 * in the named GOT cell. 364 */ 365 366 public String getCardTableAddressSymbolName() { 367 return "_aot_card_table_address"; 368 } 369 370 public String getHeapTopAddressSymbolName() { 371 return "_aot_heap_top_address"; 372 } 373 374 public String getHeapEndAddressSymbolName() { 375 return "_aot_heap_end_address"; 376 } 377 378 public String getCrcTableAddressSymbolName() { 379 return "_aot_stub_routines_crc_table_adr"; 380 } 381 382 public String getPollingPageSymbolName() { 383 return "_aot_polling_page"; 384 } 385 386 public String getResolveStaticEntrySymbolName() { 387 return "_resolve_static_entry"; 388 } 389 390 public String getResolveVirtualEntrySymbolName() { 391 return "_resolve_virtual_entry"; 392 } 393 394 public String getResolveOptVirtualEntrySymbolName() { 395 return "_resolve_opt_virtual_entry"; 396 } 397 398 public String getNarrowKlassBaseAddressSymbolName() { 399 return "_aot_narrow_klass_base_address"; 400 } 401 402 public String getNarrowOopBaseAddressSymbolName() { 403 return "_aot_narrow_oop_base_address"; 404 } 405 406 public String getLogOfHeapRegionGrainBytesSymbolName() { 407 return "_aot_log_of_heap_region_grain_bytes"; 408 } 409 410 public String getInlineContiguousAllocationSupportedSymbolName() { 411 return "_aot_inline_contiguous_allocation_supported"; 412 } 413 414 public int getCodeSegmentSize() { 415 return codeSegmentSize; 416 } 417 418 public int getCodeEntryAlignment() { 419 return codeEntryAlignment; 420 } 421 422 /** 423 * Gets the global AOT symbol associated with the function name. 424 * 425 * @param functionName function name 426 * @return AOT symbol for the given function name, or null if there is no mapping. 427 */ 428 public String getAOTSymbolForVMFunctionName(String functionName) { 429 return functionNamesToAOTSymbols.get(functionName); 430 } 431 432 private void addGlobalSymbols() { 433 // Create global symbols for all containers. 434 createContainerSymbol(codeContainer); 435 createContainerSymbol(configContainer); 436 createContainerSymbol(methodsOffsetsContainer); 437 createContainerSymbol(klassesOffsetsContainer); 438 createContainerSymbol(klassesDependenciesContainer); 439 createContainerSymbol(metaspaceGotContainer); 440 createContainerSymbol(metadataGotContainer); 441 createContainerSymbol(methodStateContainer); 442 createContainerSymbol(oopGotContainer); 443 createContainerSymbol(metaspaceNamesContainer); 444 createContainerSymbol(methodMetadataContainer); 445 createContainerSymbol(stubsOffsetsContainer); 446 createContainerSymbol(headerContainer.getContainer()); 447 createContainerSymbol(codeSegmentsContainer); 448 449 createGotSymbol(getResolveStaticEntrySymbolName()); 450 createGotSymbol(getResolveVirtualEntrySymbolName()); 451 createGotSymbol(getResolveOptVirtualEntrySymbolName()); 452 createGotSymbol(getCardTableAddressSymbolName()); 453 createGotSymbol(getHeapTopAddressSymbolName()); 454 createGotSymbol(getHeapEndAddressSymbolName()); 455 createGotSymbol(getNarrowKlassBaseAddressSymbolName()); 456 createGotSymbol(getNarrowOopBaseAddressSymbolName()); 457 createGotSymbol(getPollingPageSymbolName()); 458 createGotSymbol(getLogOfHeapRegionGrainBytesSymbolName()); 459 createGotSymbol(getInlineContiguousAllocationSupportedSymbolName()); 460 461 for (HashMap.Entry<String, String> entry : functionNamesToAOTSymbols.entrySet()) { 462 createGotSymbol(entry.getValue()); 463 } 464 } 465 466 /** 467 * Creates a global symbol of the form {@code "JVM" + container name}. 468 * 469 * @param container container to create a symbol for 470 */ 471 private static void createContainerSymbol(ByteContainer container) { 472 container.createSymbol(0, Kind.OBJECT, Binding.GLOBAL, 0, "JVM" + container.getContainerName()); 473 } 474 475 /** 476 * Creates a global GOT symbol of the form {@code "got." + name}. 477 * 478 * @param name name for the GOT symbol 479 */ 480 private void createGotSymbol(String name) { 481 String s = "got." + name; 482 Symbol gotSymbol = extLinkageGOTContainer.createGotSymbol(s); 483 extLinkageGOTContainer.createSymbol(gotSymbol.getOffset(), Kind.OBJECT, Binding.GLOBAL, 8, name); 484 } 485 486 /** 487 * Create a platform-specific binary file representing the content of the 488 * {@code BinaryContainer} object. 489 * 490 * This method is called after creating and performing any necessary changes to the contents of 491 * code stream, symbol tables and relocation tables is completely finalized 492 * 493 * @param outputFileName name of output file 494 * 495 * @throws IOException in case of file creation failure 496 */ 497 public void createBinary(String outputFileName, String aotVersion) throws IOException { 498 String osName = System.getProperty("os.name"); 499 switch (osName) { 500 case "Linux": 501 case "SunOS": 502 JELFRelocObject elfobj = new JELFRelocObject(this, outputFileName, aotVersion); 503 elfobj.createELFRelocObject(relocationTable, symbolTable.values()); 504 break; 505 case "Mac OS X": 506 JMachORelocObject machobj = new JMachORelocObject(this, outputFileName); 507 machobj.createMachORelocObject(relocationTable, symbolTable.values()); 508 break; 509 default: 510 if (osName.startsWith("Windows")) { 511 JPECoffRelocObject pecoffobj = new JPECoffRelocObject(this, outputFileName, aotVersion); 512 pecoffobj.createPECoffRelocObject(relocationTable, symbolTable.values()); 513 break; 514 } 515 else 516 throw new InternalError("Unsupported platform: " + osName); 517 } 518 } 519 520 /** 521 * Add symbol to the symbol table. If the existing symbol is undefined and the specified symbol 522 * is not undefined, replace the existing symbol information with that specified. 523 * 524 * @param symInfo symbol information to be added 525 */ 526 public void addSymbol(Symbol symInfo) { 527 if (symInfo.getName().startsWith("got.") && !(symInfo instanceof GotSymbol)) { 528 throw new InternalError("adding got. without being GotSymbol"); 529 } 530 if (symbolTable.containsKey(symInfo.getName())) { 531 throw new InternalError("Symbol: " + symInfo.getName() + " already exists in SymbolTable"); 532 } else { 533 // System.out.println("# Symbol [" + name + "] [" + symInfo.getValue() + "] [" + 534 // symInfo.getSection().getContainerName() + "] [" + symInfo.getSize() + "]"); 535 symbolTable.put(symInfo.getName(), symInfo); 536 } 537 } 538 539 public boolean addStringOffset(String name, Integer offset) { 540 offsetStringTable.put(name, offset); 541 return true; 542 } 543 544 /** 545 * Add relocation entry for {@code symName}. Multiple relocation entries for a given symbol may 546 * exist. 547 * 548 * @param info relocation information to be added 549 */ 550 public void addRelocation(Relocation info) { 551 // System.out.println("# Relocation [" + symName + "] [" + info.getOffset() + "] [" + 552 // info.getSection().getContainerName() + "] [" + info.getSymbol().getName() + "] [" + 553 // info.getSymbol().getOffset() + " @ " + info.getSymbol().getSection().getContainerName() + 554 // "]"); 555 if (relocationTable.containsKey(info.getSymbol())) { 556 relocationTable.get(info.getSymbol()).add(info); 557 } else if (uniqueRelocationTable.containsKey(info.getSymbol())) { 558 // promote 559 ArrayList<Relocation> list = new ArrayList<>(2); 560 list.add(uniqueRelocationTable.get(info.getSymbol())); 561 list.add(info); 562 relocationTable.put(info.getSymbol(), list); 563 uniqueRelocationTable.remove(info.getSymbol()); 564 } else { 565 uniqueRelocationTable.put(info.getSymbol(), info); 566 } 567 } 568 569 /** 570 * Get symbol with name {@code symName}. 571 * 572 * @param symName name of symbol for which symbol table information is being queried 573 * @return success or failure of insertion operation 574 */ 575 @Override 576 public Symbol getSymbol(String symName) { 577 return symbolTable.get(symName); 578 } 579 580 @Override 581 public Symbol createSymbol(int offset, Kind kind, Binding binding, int size, String name) { 582 if (kind != Kind.NATIVE_FUNCTION) { 583 throw new UnsupportedOperationException("Must be external functions: " + name); 584 } 585 Symbol symbol = new Symbol(offset, kind, binding, null, size, name); 586 addSymbol(symbol); 587 return symbol; 588 } 589 590 /** 591 * Get offset in got section with name {@code symName}. 592 * 593 * @param name for which String table information is being queried 594 * @return success or failure of insertion operation 595 */ 596 public Integer getStringOffset(String name) { 597 return offsetStringTable.get(name); 598 } 599 600 /** 601 * Insert {@code targetCode} to code stream with {@code size} at {@code offset}. 602 * 603 * @param targetCode byte array of native code 604 * @param offset offset at which {@code targetCode} is to be inserted 605 * @param size size of {@code targetCode} 606 */ 607 private static void appendBytes(ByteContainer byteContainer, byte[] targetCode, int offset, int size) { 608 byteContainer.appendBytes(targetCode, offset, size); 609 } 610 611 public void appendCodeBytes(byte[] targetCode, int offset, int size) { 612 appendBytes(codeContainer, targetCode, offset, size); 613 } 614 615 public void appendIntToCode(int value) { 616 codeContainer.appendInt(value); 617 } 618 619 public int appendExtLinkageGotBytes(byte[] bytes, int offset, int size) { 620 int startOffset = extLinkageGOTContainer.getByteStreamSize(); 621 appendBytes(extLinkageGOTContainer, bytes, offset, size); 622 return startOffset; 623 } 624 625 public int appendMetaspaceGotBytes(byte[] bytes, int offset, int size) { 626 int startOffset = metaspaceGotContainer.getByteStreamSize(); 627 appendBytes(metaspaceGotContainer, bytes, offset, size); 628 return startOffset; 629 } 630 631 public void addMetadataGotEntry(int offset) { 632 metadataGotContainer.appendLong(offset); 633 } 634 635 public int addMetaspaceName(String name) { 636 Integer value = metaspaceNames.get(name); 637 if (value != null) { 638 return value.intValue(); 639 } 640 // Get the current length of the stubsNameContainer 641 // align on 8-byte boundary 642 int nameOffset = alignUp(metaspaceNamesContainer, 8); 643 644 try { 645 // Add the name of the symbol to the .stubs.names section 646 // Modify them to sequence of utf8 strings with length: 647 // "<u2_size>Ljava/lang/ThreadGroup;<u2_size>addUnstarted<u2_size>()V" 648 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 649 DataOutputStream out = new DataOutputStream(bout); 650 int len = name.length(); 651 if (name.startsWith("Stub")) { // Stub 652 out.writeUTF(name); 653 } else { // Method or Klass 654 int parenthesesIndex = name.lastIndexOf('(', len - 1); 655 if (parenthesesIndex > 0) { // Method name 656 int dotIndex = name.lastIndexOf('.', parenthesesIndex - 1); 657 assert dotIndex > 0 : "method's full name should have '.' : " + name; 658 String klassName = name.substring(0, dotIndex); 659 out.writeUTF(klassName); 660 String methodName = name.substring(dotIndex + 1, parenthesesIndex); 661 out.writeUTF(methodName); 662 String signature = name.substring(parenthesesIndex, len); 663 out.writeUTF(signature); 664 } else { 665 out.writeUTF(name); // Klass 666 } 667 } 668 out.writeShort(0); // Terminate by 0. 669 byte[] b = bout.toByteArray(); 670 metaspaceNamesContainer.appendBytes(b, 0, b.length); 671 672 metaspaceNames.put(name, nameOffset); 673 return nameOffset; 674 } catch (IOException e) { 675 throw new InternalError("Failed to append bytes to stubs sections", e); 676 } 677 } 678 679 /** 680 * Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to 681 * patch. 682 * 683 * @param oopName name of the oop symbol 684 */ 685 public Integer addOopSymbol(String oopName) { 686 Integer oopGotOffset = getStringOffset(oopName); 687 if (oopGotOffset != null) { 688 return oopGotOffset; 689 } 690 return newOopSymbol(oopName); 691 } 692 693 private Integer newOopSymbol(String oopName) { 694 // Reference to String resolution (ldc). 695 int offset = oopGotContainer.getByteStreamSize(); 696 String gotName = "got.ldc." + offset; 697 Symbol relocationSymbol = oopGotContainer.createGotSymbol(gotName); 698 699 if (offset != relocationSymbol.getOffset()) { 700 throw new InternalError("offset must equal! (" + offset + " vs " + relocationSymbol.getOffset()); 701 } 702 703 addStringOffset(oopName, relocationSymbol.getOffset()); 704 return relocationSymbol.getOffset(); 705 } 706 707 public int addMetaspaceSymbol(String metaspaceName) { 708 String gotName = "got." + metaspaceName; 709 Symbol relocationSymbol = getGotSymbol(gotName); 710 int metaspaceOffset = -1; 711 if (relocationSymbol == null) { 712 // Add slots when asked in the .metaspace.got section: 713 metaspaceGotContainer.createGotSymbol(gotName); 714 } 715 return metaspaceOffset; 716 } 717 718 public Symbol getGotSymbol(String name) { 719 assert name.startsWith("got."); 720 return symbolTable.get(name); 721 } 722 723 /** 724 * Add metaspace symbol by as follows. - Adding the symbol name to the metaspace.names section - 725 * Add the offset of the name in metaspace.names to metaspace.offsets - Extend the metaspace.got 726 * section with another slot for the VM to patch 727 * 728 * @param metaspaceName name of the metaspace symbol 729 * @return the got offset in the metaspace.got of the metaspace symbol 730 */ 731 public int addTwoSlotMetaspaceSymbol(String metaspaceName) { 732 String gotName = "got." + metaspaceName; 733 Symbol previous = getGotSymbol(gotName); 734 assert previous == null : "should be called only once for: " + metaspaceName; 735 // Add slots when asked in the .metaspace.got section: 736 // First slot 737 String gotInitName = "got.init." + metaspaceName; 738 GotSymbol slot1Symbol = metaspaceGotContainer.createGotSymbol(gotInitName); 739 GotSymbol slot2Symbol = metaspaceGotContainer.createGotSymbol(gotName); 740 741 slot1Symbol.getIndex(); // check alignment and ignore result 742 // Get the index (offset/8) to the got in the .metaspace.got section 743 return slot2Symbol.getIndex(); 744 } 745 746 public int addMethodsCount(int count, ReadOnlyDataContainer container) { 747 return appendInt(count, container); 748 } 749 750 private static int appendInt(int count, ReadOnlyDataContainer container) { 751 int offset = container.getByteStreamSize(); 752 container.appendInt(count); 753 return offset; 754 } 755 756 /** 757 * Add constant data as follows. - Adding the data to the meth.constdata section 758 * 759 * @param data 760 * @param alignment 761 * @return the offset in the meth.constdata of the data 762 */ 763 public int addConstantData(byte[] data, int alignment) { 764 // Get the current length of the metaspaceNameContainer 765 int constantDataOffset = alignUp(constantDataContainer, alignment); 766 constantDataContainer.appendBytes(data, 0, data.length); 767 alignUp(constantDataContainer, alignment); // Post alignment 768 return constantDataOffset; 769 } 770 771 public int alignUp(ByteContainer container, int alignment) { 772 if (Integer.bitCount(alignment) != 1) { 773 throw new IllegalArgumentException("Must be a power of 2"); 774 } 775 int offset = container.getByteStreamSize(); 776 int aligned = (offset + (alignment - 1)) & -alignment; 777 if (aligned < offset || (aligned & (alignment - 1)) != 0) { 778 throw new RuntimeException("Error aligning: " + offset + " -> " + aligned); 779 } 780 if (aligned != offset) { 781 int nullArraySz = aligned - offset; 782 byte[] nullArray = new byte[nullArraySz]; 783 container.appendBytes(nullArray, 0, nullArraySz); 784 offset = aligned; 785 } 786 return offset; 787 } 788 789 public void addCodeSegments(int start, int end) { 790 assert (start % codeSegmentSize) == 0 : "not aligned code"; 791 int currentOffset = codeSegmentsContainer.getByteStreamSize(); 792 int offset = start / codeSegmentSize; 793 int emptySize = offset - currentOffset; 794 // add empty segments if needed 795 if (emptySize > 0) { 796 byte[] emptyArray = new byte[emptySize]; 797 for (int i = 0; i < emptySize; i++) { 798 emptyArray[i] = (byte) 0xff; 799 } 800 appendBytes(codeSegmentsContainer, emptyArray, 0, emptySize); 801 } 802 int alignedEnd = (end + (codeSegmentSize - 1)) & -codeSegmentSize; 803 int segmentsCount = (alignedEnd / codeSegmentSize) - offset; 804 byte[] segments = new byte[segmentsCount]; 805 int idx = 0; 806 for (int i = 0; i < segmentsCount; i++) { 807 segments[i] = (byte) idx; 808 idx = (idx == 0xfe) ? 1 : (idx + 1); 809 } 810 appendBytes(codeSegmentsContainer, segments, 0, segmentsCount); 811 } 812 813 public CodeContainer getExtLinkageContainer() { 814 return extLinkageContainer; 815 } 816 817 public ByteContainer getExtLinkageGOTContainer() { 818 return extLinkageGOTContainer; 819 } 820 821 public ByteContainer getMethodMetadataContainer() { 822 return methodMetadataContainer; 823 } 824 825 public ReadOnlyDataContainer getMetaspaceNamesContainer() { 826 return metaspaceNamesContainer; 827 } 828 829 public ReadOnlyDataContainer getMethodsOffsetsContainer() { 830 return methodsOffsetsContainer; 831 } 832 833 public ReadOnlyDataContainer getKlassesOffsetsContainer() { 834 return klassesOffsetsContainer; 835 } 836 837 public ReadOnlyDataContainer getKlassesDependenciesContainer() { 838 return klassesDependenciesContainer; 839 } 840 841 public ReadOnlyDataContainer getStubsOffsetsContainer() { 842 return stubsOffsetsContainer; 843 } 844 845 public ReadOnlyDataContainer getCodeSegmentsContainer() { 846 return codeSegmentsContainer; 847 } 848 849 public ReadOnlyDataContainer getConstantDataContainer() { 850 return constantDataContainer; 851 } 852 853 public ByteContainer getMetaspaceGotContainer() { 854 return metaspaceGotContainer; 855 } 856 857 public ByteContainer getMetadataGotContainer() { 858 return metadataGotContainer; 859 } 860 861 public ByteContainer getMethodStateContainer() { 862 return methodStateContainer; 863 } 864 865 public ByteContainer getOopGotContainer() { 866 return oopGotContainer; 867 } 868 869 public CodeContainer getCodeContainer() { 870 return codeContainer; 871 } 872 873 public ReadOnlyDataContainer getConfigContainer() { 874 return configContainer; 875 } 876 877 public Map<Symbol, Relocation> getUniqueRelocationTable() { 878 return uniqueRelocationTable; 879 } 880 881 public HeaderContainer getHeaderContainer() { 882 return headerContainer; 883 } 884 885 }