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