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