openjdk-17/8264805-Backport-Ahead-of-Time-Compiler.patch
2025-02-25 16:45:21 +08:00

33087 lines
1.3 MiB

---
make/RunTests.gmk | 124 +-
make/RunTestsPrebuilt.gmk | 24 +-
make/autoconf/jvm-features.m4 | 62 +-
make/autoconf/spec.gmk.in | 6 +-
make/autoconf/toolchain.m4 | 6 +
make/common/Modules.gmk | 7 +-
make/conf/build-module-sets.conf | 3 +-
make/conf/jib-profiles.js | 3 +-
make/conf/module-loader-map.conf | 3 +-
make/hotspot/lib/JvmFeatures.gmk | 10 +-
.../visualstudio/hotspot/CreateVSProject.gmk | 3 +-
make/modules/jdk.aot/Java.gmk | 54 +
make/modules/jdk.aot/Launcher.gmk | 54 +
.../modules/jdk.internal.vm.compiler/Java.gmk | 3 +-
src/hotspot/cpu/aarch64/aarch64.ad | 6 +-
.../cpu/aarch64/c1_LIRAssembler_aarch64.hpp | 3 +-
.../cpu/aarch64/c1_LIRGenerator_aarch64.cpp | 2 +-
.../cpu/aarch64/compiledIC_aarch64.cpp | 78 +-
.../cpu/aarch64/compiledIC_aot_aarch64.cpp | 104 ++
.../c1/shenandoahBarrierSetC1_aarch64.cpp | 4 +-
.../cpu/aarch64/macroAssembler_aarch64.hpp | 6 +-
.../cpu/aarch64/nativeInst_aarch64.cpp | 17 +-
.../cpu/aarch64/nativeInst_aarch64.hpp | 14 +-
.../cpu/aarch64/sharedRuntime_aarch64.cpp | 16 +-
.../templateInterpreterGenerator_aarch64.cpp | 6 +-
.../cpu/aarch64/templateTable_aarch64.cpp | 10 +-
src/hotspot/cpu/arm/c1_LIRAssembler_arm.hpp | 3 +-
src/hotspot/cpu/arm/compiledIC_arm.cpp | 6 +-
src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp | 11 +-
src/hotspot/cpu/ppc/compiledIC_ppc.cpp | 8 +-
src/hotspot/cpu/s390/c1_LIRAssembler_s390.hpp | 5 +-
src/hotspot/cpu/s390/compiledIC_s390.cpp | 8 +-
src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp | 14 +-
src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp | 3 +-
src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp | 4 +-
src/hotspot/cpu/x86/c1_Runtime1_x86.cpp | 4 +-
src/hotspot/cpu/x86/compiledIC_aot_x86_64.cpp | 122 ++
src/hotspot/cpu/x86/compiledIC_x86.cpp | 76 +-
src/hotspot/cpu/x86/globalDefinitions_x86.hpp | 4 +-
src/hotspot/cpu/x86/nativeInst_x86.hpp | 9 +-
src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 12 +-
.../x86/templateInterpreterGenerator_x86.cpp | 4 +-
src/hotspot/cpu/x86/x86_64.ad | 5 +-
src/hotspot/os/windows/os_windows.cpp | 21 +-
src/hotspot/share/aot/aotCodeHeap.cpp | 1116 +++++++++++++++++
src/hotspot/share/aot/aotCodeHeap.hpp | 310 +++++
src/hotspot/share/aot/aotCompiledMethod.cpp | 415 ++++++
src/hotspot/share/aot/aotCompiledMethod.hpp | 320 +++++
src/hotspot/share/aot/aotLoader.cpp | 335 +++++
src/hotspot/share/aot/aotLoader.hpp | 74 ++
src/hotspot/share/aot/aotLoader.inline.hpp | 39 +
src/hotspot/share/aot/compiledIC_aot.cpp | 37 +
src/hotspot/share/aot/compiledIC_aot.hpp | 83 ++
src/hotspot/share/asm/codeBuffer.hpp | 14 +
src/hotspot/share/c1/c1_Compilation.hpp | 4 +-
src/hotspot/share/c1/c1_LIRAssembler.cpp | 4 +-
src/hotspot/share/c1/c1_LIRAssembler.hpp | 8 +-
src/hotspot/share/c1/c1_LIRGenerator.cpp | 6 +-
.../share/classfile/classFileParser.cpp | 25 +-
.../share/classfile/classFileStream.cpp | 11 +-
.../share/classfile/systemDictionary.cpp | 22 +-
src/hotspot/share/code/codeBlob.hpp | 18 +-
src/hotspot/share/code/codeCache.cpp | 29 +-
src/hotspot/share/code/codeCache.hpp | 8 +-
src/hotspot/share/code/compiledIC.cpp | 51 +-
src/hotspot/share/code/compiledIC.hpp | 34 +-
src/hotspot/share/code/compiledMethod.cpp | 3 +-
src/hotspot/share/code/compiledMethod.hpp | 7 +-
src/hotspot/share/code/nmethod.cpp | 26 +-
src/hotspot/share/code/relocInfo.cpp | 18 +-
src/hotspot/share/code/relocInfo.hpp | 16 +-
.../share/compiler/compilationPolicy.cpp | 86 +-
.../share/compiler/compilationPolicy.hpp | 4 +-
.../share/compiler/compilerDefinitions.cpp | 31 +-
.../share/compiler/compilerDefinitions.hpp | 17 +-
.../share/compiler/compiler_globals.hpp | 29 +-
src/hotspot/share/compiler/disassembler.cpp | 22 +-
src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp | 3 +-
src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp | 3 +-
src/hotspot/share/gc/g1/g1RootProcessor.cpp | 14 +-
src/hotspot/share/gc/g1/g1RootProcessor.hpp | 3 +-
.../share/gc/parallel/psParallelCompact.cpp | 16 +-
src/hotspot/share/gc/parallel/psScavenge.cpp | 8 +-
.../share/gc/shared/genCollectedHeap.cpp | 11 +-
.../gc/shenandoah/shenandoahArguments.cpp | 10 +-
.../leakprofiler/chains/rootSetClosure.cpp | 8 +-
.../leakprofiler/checkpoint/rootResolver.cpp | 24 +-
.../jfr/leakprofiler/utilities/rootType.cpp | 4 +-
.../jfr/leakprofiler/utilities/rootType.hpp | 3 +-
src/hotspot/share/jvmci/compilerRuntime.cpp | 283 +++++
src/hotspot/share/jvmci/compilerRuntime.hpp | 51 +
.../share/jvmci/jvmciCodeInstaller.cpp | 175 ++-
.../share/jvmci/jvmciCodeInstaller.hpp | 63 +-
src/hotspot/share/jvmci/jvmciCompiler.cpp | 4 +-
src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 92 +-
.../jvmci/vmStructs_compiler_runtime.hpp | 45 +
src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 7 +-
src/hotspot/share/logging/logTag.hpp | 6 +-
src/hotspot/share/memory/heap.hpp | 13 +-
src/hotspot/share/memory/metaspace.cpp | 8 +-
src/hotspot/share/memory/universe.cpp | 9 +-
src/hotspot/share/memory/virtualspace.hpp | 10 +-
src/hotspot/share/oops/compressedOops.cpp | 15 +-
src/hotspot/share/oops/instanceKlass.cpp | 92 +-
src/hotspot/share/oops/instanceKlass.hpp | 54 +-
.../share/oops/instanceKlass.inline.hpp | 31 +-
src/hotspot/share/oops/method.hpp | 20 +-
src/hotspot/share/oops/methodCounters.cpp | 13 +-
src/hotspot/share/oops/methodCounters.hpp | 10 +-
src/hotspot/share/opto/c2compiler.cpp | 4 +-
src/hotspot/share/opto/output.cpp | 6 +-
.../share/prims/jvmtiRedefineClasses.cpp | 17 +-
src/hotspot/share/prims/jvmtiTagMap.cpp | 4 +-
src/hotspot/share/prims/whitebox.cpp | 17 +-
.../share/runtime/abstract_vm_version.cpp | 10 +-
src/hotspot/share/runtime/arguments.cpp | 17 +-
src/hotspot/share/runtime/deoptimization.cpp | 12 +-
src/hotspot/share/runtime/frame.cpp | 10 +-
src/hotspot/share/runtime/globals.hpp | 19 +
src/hotspot/share/runtime/init.cpp | 8 +-
src/hotspot/share/runtime/java.cpp | 11 +-
src/hotspot/share/runtime/sharedRuntime.cpp | 9 +-
src/hotspot/share/runtime/thread.cpp | 15 +-
src/hotspot/share/runtime/vframe_hp.cpp | 4 +-
src/hotspot/share/runtime/vmStructs.cpp | 4 +-
src/hotspot/share/utilities/macros.hpp | 20 +-
src/hotspot/share/utilities/vmError.cpp | 6 +-
.../jaotc/binformat/BinaryContainer.java | 959 ++++++++++++++
.../tools/jaotc/binformat/ByteContainer.java | 261 ++++
.../tools/jaotc/binformat/CodeContainer.java | 36 +
.../jdk/tools/jaotc/binformat/Container.java | 34 +
.../jdk/tools/jaotc/binformat/GotSymbol.java | 64 +
.../jaotc/binformat/HeaderContainer.java | 94 ++
.../tools/jaotc/binformat/NativeSymbol.java | 53 +
.../binformat/ReadOnlyDataContainer.java | 33 +
.../jdk/tools/jaotc/binformat/Relocation.java | 97 ++
.../src/jdk/tools/jaotc/binformat/Symbol.java | 154 +++
.../tools/jaotc/binformat/SymbolTable.java | 34 +
.../binformat/elf/AArch64JELFRelocObject.java | 118 ++
.../binformat/elf/AMD64JELFRelocObject.java | 111 ++
.../jdk/tools/jaotc/binformat/elf/Elf.java | 277 ++++
.../jaotc/binformat/elf/ElfByteBuffer.java | 45 +
.../jaotc/binformat/elf/ElfContainer.java | 89 ++
.../tools/jaotc/binformat/elf/ElfHeader.java | 75 ++
.../jaotc/binformat/elf/ElfRelocEntry.java | 47 +
.../jaotc/binformat/elf/ElfRelocTable.java | 70 ++
.../tools/jaotc/binformat/elf/ElfSection.java | 157 +++
.../tools/jaotc/binformat/elf/ElfSymbol.java | 53 +
.../tools/jaotc/binformat/elf/ElfSymtab.java | 146 +++
.../jaotc/binformat/elf/ElfTargetInfo.java | 85 ++
.../jaotc/binformat/elf/JELFRelocObject.java | 328 +++++
.../binformat/macho/JMachORelocObject.java | 429 +++++++
.../tools/jaotc/binformat/macho/MachO.java | 311 +++++
.../binformat/macho/MachOByteBuffer.java | 43 +
.../jaotc/binformat/macho/MachOContainer.java | 83 ++
.../jaotc/binformat/macho/MachODySymtab.java | 51 +
.../jaotc/binformat/macho/MachOHeader.java | 57 +
.../binformat/macho/MachORelocEntry.java | 55 +
.../binformat/macho/MachORelocTable.java | 75 ++
.../jaotc/binformat/macho/MachOSection.java | 109 ++
.../jaotc/binformat/macho/MachOSegment.java | 53 +
.../jaotc/binformat/macho/MachOSymbol.java | 52 +
.../jaotc/binformat/macho/MachOSymtab.java | 209 +++
.../binformat/macho/MachOTargetInfo.java | 87 ++
.../jaotc/binformat/macho/MachOVersion.java | 47 +
.../binformat/pecoff/JPECoffRelocObject.java | 365 ++++++
.../tools/jaotc/binformat/pecoff/PECoff.java | 207 +++
.../binformat/pecoff/PECoffByteBuffer.java | 40 +
.../binformat/pecoff/PECoffContainer.java | 89 ++
.../jaotc/binformat/pecoff/PECoffHeader.java | 65 +
.../binformat/pecoff/PECoffRelocEntry.java | 47 +
.../binformat/pecoff/PECoffRelocTable.java | 86 ++
.../jaotc/binformat/pecoff/PECoffSection.java | 133 ++
.../jaotc/binformat/pecoff/PECoffSymbol.java | 58 +
.../jaotc/binformat/pecoff/PECoffSymtab.java | 150 +++
.../binformat/pecoff/PECoffTargetInfo.java | 74 ++
.../src/jdk/tools/jaotc/test/HelloWorld.java | 31 +
.../test/NativeOrderOutputStreamTest.java | 136 ++
.../jaotc/test/collect/ClassSearchTest.java | 219 ++++
.../jaotc/test/collect/ClassSourceTest.java | 66 +
.../jaotc/test/collect/FakeFileSupport.java | 114 ++
.../jaotc/test/collect/FakeSearchPath.java | 51 +
.../jaotc/test/collect/SearchPathTest.java | 122 ++
.../jdk/tools/jaotc/test/collect/Utils.java | 62 +
.../DirectorySourceProviderTest.java | 91 ++
.../collect/jar/JarSourceProviderTest.java | 127 ++
.../module/ModuleSourceProviderTest.java | 102 ++
.../src/jdk/tools/jaotc/AOTBackend.java | 176 +++
.../jdk/tools/jaotc/AOTCompilationTask.java | 211 ++++
.../src/jdk/tools/jaotc/AOTCompiledClass.java | 471 +++++++
.../src/jdk/tools/jaotc/AOTCompiler.java | 169 +++
.../jdk/tools/jaotc/AOTDynamicTypeStore.java | 172 +++
.../jaotc/AOTHotSpotResolvedJavaMethod.java | 64 +
.../src/jdk/tools/jaotc/AOTStub.java | 63 +
.../src/jdk/tools/jaotc/CallInfo.java | 105 ++
.../tools/jaotc/CallSiteRelocationInfo.java | 44 +
.../tools/jaotc/CallSiteRelocationSymbol.java | 84 ++
.../src/jdk/tools/jaotc/CodeOffsets.java | 102 ++
.../jdk/tools/jaotc/CodeSectionProcessor.java | 149 +++
.../src/jdk/tools/jaotc/Collector.java | 214 ++++
.../src/jdk/tools/jaotc/CompilationSpec.java | 127 ++
.../jdk/tools/jaotc/CompiledMethodInfo.java | 341 +++++
.../src/jdk/tools/jaotc/DataBuilder.java | 243 ++++
.../jdk/tools/jaotc/DataPatchProcessor.java | 165 +++
.../jdk/tools/jaotc/ELFMacroAssembler.java | 58 +
.../jaotc/ForeignCallSiteRelocationInfo.java | 75 ++
.../ForeignCallSiteRelocationSymbol.java | 41 +
.../ForeignGotCallSiteRelocationSymbol.java | 72 ++
.../src/jdk/tools/jaotc/GraalFilters.java | 147 +++
.../jdk/tools/jaotc/InfopointProcessor.java | 149 +++
.../jdk/tools/jaotc/InstructionDecoder.java | 53 +
.../jaotc/JavaCallSiteRelocationInfo.java | 43 +
.../jaotc/JavaCallSiteRelocationSymbol.java | 155 +++
.../src/jdk/tools/jaotc/JavaMethodInfo.java | 61 +
.../src/jdk/tools/jaotc/Linker.java | 261 ++++
.../src/jdk/tools/jaotc/LoadedClass.java | 73 ++
.../src/jdk/tools/jaotc/LogPrinter.java | 198 +++
.../src/jdk/tools/jaotc/Main.java | 356 ++++++
.../src/jdk/tools/jaotc/MarkProcessor.java | 137 ++
.../src/jdk/tools/jaotc/MetadataBuilder.java | 251 ++++
.../src/jdk/tools/jaotc/Options.java | 300 +++++
.../StubDirectCallSiteRelocationSymbol.java | 41 +
.../src/jdk/tools/jaotc/StubInformation.java | 124 ++
.../src/jdk/tools/jaotc/Timer.java | 45 +
.../aarch64/AArch64ELFMacroAssembler.java | 131 ++
.../aarch64/AArch64InstructionDecoder.java | 47 +
.../jaotc/amd64/AMD64ELFMacroAssembler.java | 122 ++
.../jaotc/amd64/AMD64InstructionDecoder.java | 569 +++++++++
.../jdk/tools/jaotc/collect/ClassSearch.java | 116 ++
.../jdk/tools/jaotc/collect/ClassSource.java | 66 +
.../jdk/tools/jaotc/collect/FileSupport.java | 103 ++
.../tools/jaotc/collect/FileSystemFinder.java | 83 ++
.../jdk/tools/jaotc/collect/SearchFor.java | 57 +
.../jdk/tools/jaotc/collect/SearchPath.java | 89 ++
.../tools/jaotc/collect/SourceProvider.java | 32 +
.../collect/classname/ClassNameSource.java | 45 +
.../classname/ClassNameSourceProvider.java | 70 ++
.../collect/directory/DirectorySource.java | 56 +
.../directory/DirectorySourceProvider.java | 71 ++
.../jaotc/collect/jar/JarFileSource.java | 58 +
.../jaotc/collect/jar/JarSourceProvider.java | 86 ++
.../jaotc/collect/module/ModuleSource.java | 60 +
.../collect/module/ModuleSourceProvider.java | 85 ++
.../jaotc/utils/NativeOrderOutputStream.java | 193 +++
src/jdk.aot/share/classes/module-info.java | 37 +
src/jdk.aot/share/man/jaotc.1 | 209 +++
.../sun/jvm/hotspot/code/CodeBlob.java | 4 +-
.../sun/jvm/hotspot/oops/InstanceKlass.java | 29 +-
.../classes/sun/jvm/hotspot/runtime/VM.java | 19 +-
.../share/classes/module-info.java | 31 +
.../core/test/CheckGraalInvariants.java | 1 +
.../core/test/VerifySystemPropertyUsage.java | 4 +
test/hotspot/jtreg/ProblemList-aot.txt | 82 ++
test/hotspot/jtreg/TEST.ROOT | 2 +
test/hotspot/jtreg/TEST.groups | 7 +-
.../applications/ctw/modules/jdk_aot.java | 38 +
.../jtreg/compiler/aot/AotCompiler.java | 280 +++++
.../compiler/aot/DeoptimizationTest.java | 86 ++
.../jtreg/compiler/aot/HelloWorldPrinter.java | 41 +
.../jtreg/compiler/aot/RecompilationTest.java | 110 ++
.../jtreg/compiler/aot/SharedUsageTest.java | 79 ++
.../jtreg/compiler/aot/TestHeapBase.java | 81 ++
.../fromAot/AotInvokeDynamic2AotTest.java | 43 +
.../AotInvokeDynamic2CompiledTest.java | 48 +
.../AotInvokeDynamic2InterpretedTest.java | 44 +
.../fromAot/AotInvokeDynamic2NativeTest.java | 42 +
.../fromAot/AotInvokeInterface2AotTest.java | 41 +
.../AotInvokeInterface2CompiledTest.java | 47 +
.../AotInvokeInterface2InterpretedTest.java | 42 +
.../AotInvokeInterface2NativeTest.java | 40 +
.../fromAot/AotInvokeSpecial2AotTest.java | 41 +
.../AotInvokeSpecial2CompiledTest.java | 46 +
.../AotInvokeSpecial2InterpretedTest.java | 42 +
.../fromAot/AotInvokeSpecial2NativeTest.java | 40 +
.../fromAot/AotInvokeStatic2AotTest.java | 41 +
.../fromAot/AotInvokeStatic2CompiledTest.java | 46 +
.../AotInvokeStatic2InterpretedTest.java | 42 +
.../fromAot/AotInvokeStatic2NativeTest.java | 40 +
.../fromAot/AotInvokeVirtual2AotTest.java | 41 +
.../AotInvokeVirtual2CompiledTest.java | 46 +
.../AotInvokeVirtual2InterpretedTest.java | 42 +
.../fromAot/AotInvokeVirtual2NativeTest.java | 40 +
.../CompiledInvokeDynamic2AotTest.java | 48 +
.../CompiledInvokeInterface2AotTest.java | 47 +
.../CompiledInvokeSpecial2AotTest.java | 46 +
.../CompiledInvokeStatic2AotTest.java | 46 +
.../CompiledInvokeVirtual2AotTest.java | 46 +
.../InterpretedInvokeDynamic2AotTest.java | 44 +
.../InterpretedInvokeInterface2AotTest.java | 42 +
.../InterpretedInvokeSpecial2AotTest.java | 42 +
.../InterpretedInvokeStatic2AotTest.java | 42 +
.../InterpretedInvokeVirtual2AotTest.java | 42 +
.../NativeInvokeSpecial2AotTest.java | 40 +
.../NativeInvokeStatic2AotTest.java | 40 +
.../NativeInvokeVirtual2AotTest.java | 40 +
.../aot/cli/AotLibraryNegativeBase.java | 49 +
.../aot/cli/DisabledAOTWithLibraryTest.java | 66 +
.../aot/cli/IncorrectAOTLibraryTest.java | 48 +
.../aot/cli/MultipleAOTLibraryTest.java | 96 ++
.../aot/cli/NonExistingAOTLibraryTest.java | 50 +
.../aot/cli/SingleAOTLibraryTest.java | 77 ++
.../compiler/aot/cli/SingleAOTOptionTest.java | 86 ++
.../compiler/aot/cli/jaotc/AtFileTest.java | 60 +
.../ClasspathOptionUnknownClassTest.java | 47 +
.../jaotc/CompileAbsoluteDirectoryTest.java | 60 +
.../aot/cli/jaotc/CompileClassTest.java | 52 +
.../cli/jaotc/CompileClassWithDebugTest.java | 52 +
.../aot/cli/jaotc/CompileDirectoryTest.java | 53 +
.../aot/cli/jaotc/CompileJarTest.java | 75 ++
.../aot/cli/jaotc/CompileModuleTest.java | 75 ++
.../aot/cli/jaotc/IgnoreErrorsTest.java | 88 ++
.../compiler/aot/cli/jaotc/IllegalClass.jasm | 27 +
.../aot/cli/jaotc/JaotcTestHelper.java | 93 ++
.../cli/jaotc/ListOptionNotExistingTest.java | 54 +
.../aot/cli/jaotc/ListOptionTest.java | 76 ++
.../cli/jaotc/ListOptionWrongFileTest.java | 63 +
.../aot/cli/jaotc/data/HelloWorldOne.java | 32 +
.../aot/cli/jaotc/data/HelloWorldTwo.java | 33 +
.../compiler/aot/fingerprint/CDSDumper.java | 69 +
.../compiler/aot/fingerprint/CDSRunner.java | 42 +
.../compiler/aot/fingerprint/SelfChanged.java | 132 ++
.../aot/fingerprint/SelfChangedCDS.java | 90 ++
.../aot/fingerprint/SuperChanged.java | 113 ++
.../test/NativeOrderOutputStreamTest.java | 131 ++
.../jaotc/test/collect/ClassSearchTest.java | 211 ++++
.../jaotc/test/collect/ClassSourceTest.java | 64 +
.../jaotc/test/collect/FakeFileSupport.java | 112 ++
.../jaotc/test/collect/FakeSearchPath.java | 49 +
.../jaotc/test/collect/SearchPathTest.java | 118 ++
.../jdk/tools/jaotc/test/collect/Utils.java | 58 +
.../DirectorySourceProviderTest.java | 89 ++
.../collect/jar/JarSourceProviderTest.java | 128 ++
.../module/ModuleSourceProviderTest.java | 103 ++
.../compiler/aot/scripts/HelloWorld.java | 5 +
.../jtreg/compiler/aot/scripts/InitGraal.java | 30 +
.../hotspot/jtreg/compiler/aot/scripts/README | 32 +
.../compiler/aot/scripts/build-bootmodules.sh | 106 ++
.../aot/scripts/build-jdk.vm-modules.sh | 110 ++
.../jtreg/compiler/aot/scripts/empty.js | 1 +
.../compiler/aot/scripts/java.base-list.txt | 20 +
.../scripts/jdk.internal.vm.compiler-list.txt | 45 +
.../jtreg/compiler/aot/scripts/test-env.sh | 42 +
.../jtreg/compiler/aot/scripts/test-graal.sh | 62 +
.../compiler/aot/scripts/test-helloworld.sh | 97 ++
.../jtreg/compiler/aot/scripts/test-jaotc.sh | 43 +
.../jtreg/compiler/aot/scripts/test-javac.sh | 157 +++
.../ClassAndLibraryNotMatchTest.java | 124 ++
.../vmflags/BasicFlagsChange.java | 112 ++
.../vmflags/NotTrackedFlagTest.java | 33 +
.../verification/vmflags/TrackedFlagTest.java | 34 +
.../intrinsics/bigInteger/TestMulAdd.java | 2 +
.../sha/sanity/TestMD5Intrinsics.java | 4 +-
.../sanity/TestMD5MultiBlockIntrinsics.java | 4 +-
.../sha/sanity/TestSHA1Intrinsics.java | 4 +-
.../sanity/TestSHA1MultiBlockIntrinsics.java | 4 +-
.../sha/sanity/TestSHA256Intrinsics.java | 4 +-
.../TestSHA256MultiBlockIntrinsics.java | 4 +-
.../sha/sanity/TestSHA3Intrinsics.java | 6 +-
.../sanity/TestSHA3MultiBlockIntrinsics.java | 6 +-
.../sha/sanity/TestSHA512Intrinsics.java | 4 +-
.../TestSHA512MultiBlockIntrinsics.java | 4 +-
.../whitebox/CompilerWhiteBoxTest.java | 4 +-
.../CompressedClassPointers.java | 5 +-
.../cds/TestInterpreterMethodEntries.java | 4 +-
.../dcmd/compiler/CodelistTest.java | 4 +-
.../jtreg/testlibrary/jittester/Makefile | 13 +-
.../jittester/conf/default.properties | 2 +-
.../jittester/AotTestGeneratorsFactory.java | 72 ++
.../vm/compiler/CodeCacheInfo/Test.java | 11 +-
test/jdk/ProblemList-aot.txt | 34 +
.../FieldSetAccessibleTest.java | 6 +-
.../jdk/modules/etc/UpgradeableModules.java | 3 +-
test/jdk/tools/jimage/VerifyJimage.java | 2 +-
test/jdk/tools/launcher/HelpFlagsTest.java | 5 +-
test/jdk/tools/launcher/VersionCheck.java | 4 +-
test/jtreg-ext/requires/VMProps.java | 42 +
test/lib/jdk/test/whitebox/WhiteBox.java | 3 +
test/lib/jdk/test/whitebox/code/CodeBlob.java | 10 +-
378 files changed, 27158 insertions(+), 310 deletions(-)
create mode 100644 make/modules/jdk.aot/Java.gmk
create mode 100644 make/modules/jdk.aot/Launcher.gmk
create mode 100644 src/hotspot/cpu/aarch64/compiledIC_aot_aarch64.cpp
create mode 100644 src/hotspot/cpu/x86/compiledIC_aot_x86_64.cpp
create mode 100644 src/hotspot/share/aot/aotCodeHeap.cpp
create mode 100644 src/hotspot/share/aot/aotCodeHeap.hpp
create mode 100644 src/hotspot/share/aot/aotCompiledMethod.cpp
create mode 100644 src/hotspot/share/aot/aotCompiledMethod.hpp
create mode 100644 src/hotspot/share/aot/aotLoader.cpp
create mode 100644 src/hotspot/share/aot/aotLoader.hpp
create mode 100644 src/hotspot/share/aot/aotLoader.inline.hpp
create mode 100644 src/hotspot/share/aot/compiledIC_aot.cpp
create mode 100644 src/hotspot/share/aot/compiledIC_aot.hpp
create mode 100644 src/hotspot/share/jvmci/compilerRuntime.cpp
create mode 100644 src/hotspot/share/jvmci/compilerRuntime.hpp
create mode 100644 src/hotspot/share/jvmci/vmStructs_compiler_runtime.hpp
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ByteContainer.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/CodeContainer.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Container.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/GotSymbol.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/HeaderContainer.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/NativeSymbol.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ReadOnlyDataContainer.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Relocation.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Symbol.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/SymbolTable.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/AArch64JELFRelocObject.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/AMD64JELFRelocObject.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/Elf.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfByteBuffer.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfContainer.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfHeader.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocEntry.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocTable.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSection.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymbol.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymtab.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfTargetInfo.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/JELFRelocObject.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/JMachORelocObject.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachO.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOByteBuffer.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOContainer.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachODySymtab.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOHeader.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocEntry.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocTable.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSection.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSegment.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymbol.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymtab.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOTargetInfo.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOVersion.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/JPECoffRelocObject.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoff.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffByteBuffer.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffContainer.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffHeader.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocEntry.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocTable.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSection.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymbol.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymtab.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffTargetInfo.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/HelloWorld.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/NativeOrderOutputStreamTest.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/Utils.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiler.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTDynamicTypeStore.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallInfo.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationInfo.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeOffsets.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeSectionProcessor.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Collector.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompilationSpec.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ELFMacroAssembler.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationInfo.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationSymbol.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignGotCallSiteRelocationSymbol.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InfopointProcessor.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InstructionDecoder.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationInfo.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaMethodInfo.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Linker.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LogPrinter.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Options.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubDirectCallSiteRelocationSymbol.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubInformation.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Timer.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/aarch64/AArch64ELFMacroAssembler.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/aarch64/AArch64InstructionDecoder.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64ELFMacroAssembler.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64InstructionDecoder.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java
create mode 100644 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/NativeOrderOutputStream.java
create mode 100644 src/jdk.aot/share/classes/module-info.java
create mode 100644 src/jdk.aot/share/man/jaotc.1
create mode 100644 test/hotspot/jtreg/ProblemList-aot.txt
create mode 100644 test/hotspot/jtreg/applications/ctw/modules/jdk_aot.java
create mode 100644 test/hotspot/jtreg/compiler/aot/AotCompiler.java
create mode 100644 test/hotspot/jtreg/compiler/aot/DeoptimizationTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/HelloWorldPrinter.java
create mode 100644 test/hotspot/jtreg/compiler/aot/RecompilationTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/SharedUsageTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/TestHeapBase.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2CompiledTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2InterpretedTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2NativeTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeInterface2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeInterface2CompiledTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeInterface2InterpretedTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeInterface2NativeTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeSpecial2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeSpecial2CompiledTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeSpecial2InterpretedTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeSpecial2NativeTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeStatic2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeStatic2CompiledTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeStatic2InterpretedTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeStatic2NativeTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeVirtual2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeVirtual2CompiledTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeVirtual2InterpretedTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeVirtual2NativeTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeDynamic2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeInterface2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeSpecial2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeStatic2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeVirtual2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeDynamic2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeInterface2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeSpecial2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeStatic2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeVirtual2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromNative/NativeInvokeSpecial2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromNative/NativeInvokeStatic2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/calls/fromNative/NativeInvokeVirtual2AotTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/AotLibraryNegativeBase.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/DisabledAOTWithLibraryTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/IncorrectAOTLibraryTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/MultipleAOTLibraryTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/NonExistingAOTLibraryTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/SingleAOTLibraryTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/SingleAOTOptionTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/jaotc/AtFileTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/jaotc/ClasspathOptionUnknownClassTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileAbsoluteDirectoryTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileClassTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileClassWithDebugTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileDirectoryTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileJarTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileModuleTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/jaotc/IgnoreErrorsTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/jaotc/IllegalClass.jasm
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/jaotc/JaotcTestHelper.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/jaotc/ListOptionNotExistingTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/jaotc/ListOptionTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/jaotc/ListOptionWrongFileTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/jaotc/data/HelloWorldOne.java
create mode 100644 test/hotspot/jtreg/compiler/aot/cli/jaotc/data/HelloWorldTwo.java
create mode 100644 test/hotspot/jtreg/compiler/aot/fingerprint/CDSDumper.java
create mode 100644 test/hotspot/jtreg/compiler/aot/fingerprint/CDSRunner.java
create mode 100644 test/hotspot/jtreg/compiler/aot/fingerprint/SelfChanged.java
create mode 100644 test/hotspot/jtreg/compiler/aot/fingerprint/SelfChangedCDS.java
create mode 100644 test/hotspot/jtreg/compiler/aot/fingerprint/SuperChanged.java
create mode 100644 test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/NativeOrderOutputStreamTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java
create mode 100644 test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java
create mode 100644 test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/Utils.java
create mode 100644 test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/scripts/HelloWorld.java
create mode 100644 test/hotspot/jtreg/compiler/aot/scripts/InitGraal.java
create mode 100644 test/hotspot/jtreg/compiler/aot/scripts/README
create mode 100644 test/hotspot/jtreg/compiler/aot/scripts/build-bootmodules.sh
create mode 100644 test/hotspot/jtreg/compiler/aot/scripts/build-jdk.vm-modules.sh
create mode 100644 test/hotspot/jtreg/compiler/aot/scripts/empty.js
create mode 100644 test/hotspot/jtreg/compiler/aot/scripts/java.base-list.txt
create mode 100644 test/hotspot/jtreg/compiler/aot/scripts/jdk.internal.vm.compiler-list.txt
create mode 100644 test/hotspot/jtreg/compiler/aot/scripts/test-env.sh
create mode 100644 test/hotspot/jtreg/compiler/aot/scripts/test-graal.sh
create mode 100644 test/hotspot/jtreg/compiler/aot/scripts/test-helloworld.sh
create mode 100644 test/hotspot/jtreg/compiler/aot/scripts/test-jaotc.sh
create mode 100644 test/hotspot/jtreg/compiler/aot/scripts/test-javac.sh
create mode 100644 test/hotspot/jtreg/compiler/aot/verification/ClassAndLibraryNotMatchTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/verification/vmflags/BasicFlagsChange.java
create mode 100644 test/hotspot/jtreg/compiler/aot/verification/vmflags/NotTrackedFlagTest.java
create mode 100644 test/hotspot/jtreg/compiler/aot/verification/vmflags/TrackedFlagTest.java
create mode 100644 test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/AotTestGeneratorsFactory.java
create mode 100644 test/jdk/ProblemList-aot.txt
diff --git a/make/RunTests.gmk b/make/RunTests.gmk
index 57a282bfd..9fad1ed43 100644
--- a/make/RunTests.gmk
+++ b/make/RunTests.gmk
@@ -46,7 +46,7 @@ endif
$(eval $(call ParseKeywordVariable, TEST_OPTS, \
SINGLE_KEYWORDS := JOBS TIMEOUT_FACTOR JCOV JCOV_DIFF_CHANGESET, \
- STRING_KEYWORDS := VM_OPTIONS JAVA_OPTIONS, \
+ STRING_KEYWORDS := VM_OPTIONS JAVA_OPTIONS AOT_MODULES, \
))
# Helper function to propagate TEST_OPTS values.
@@ -134,6 +134,96 @@ ifeq ($(GCOV_ENABLED), true)
JTREG_COV_OPTIONS += -e:GCOV_PREFIX="$(GCOV_OUTPUT_DIR)"
endif
+################################################################################
+# Optionally create AOT libraries for specified modules before running tests.
+# Note, this could not be done during JDK build time.
+################################################################################
+# Parameter 1 is the name of the rule.
+#
+# Remaining parameters are named arguments.
+# MODULE The module to generate a library for
+# BIN Output directory in which to put the library
+# VM_OPTIONS List of JVM arguments to use when creating library
+# OPTIONS_VAR Name of variable to put AOT java options in
+# PREREQS_VAR Name of variable to put all AOT prerequisite rule targets in
+# for test rules to depend on
+#
+SetupAotModule = $(NamedParamsMacroTemplate)
+define SetupAotModuleBody
+ $1_AOT_LIB := $$($1_BIN)/$$(call SHARED_LIBRARY,$$($1_MODULE))
+ $1_AOT_CCLIST := $$(wildcard $$(TOPDIR)/test/hotspot/jtreg/compiler/aot/scripts/$$($1_MODULE)-list.txt)
+
+ # Create jaotc flags.
+ # VM flags which don't affect AOT code generation are filtered out:
+ # -Xcomp, -XX:+-TieredCompilation
+ $1_JAOTC_OPTS := \
+ -J-Xmx4g --info \
+ $$(addprefix -J, $$(filter-out -Xcomp %TieredCompilation, $$($1_VM_OPTIONS))) \
+ $$(addprefix --compile-commands$(SPACE), $$($1_AOT_CCLIST)) \
+ --linker-path $$(LD_JAOTC) \
+ #
+
+ ifneq ($$(filter -ea, $$($1_VM_OPTIONS)), )
+ $1_JAOTC_OPTS += --compile-with-assertions
+ endif
+
+ ifneq ($$(filter -XX:+VerifyOops, $$($1_VM_OPTIONS)), )
+ $1_JAOTC_OPTS += -J-Dgraal.AOTVerifyOops=true
+ endif
+
+ $$($1_AOT_LIB): $$(JDK_UNDER_TEST)/release \
+ $$(call DependOnVariable, $1_JAOTC_OPTS) \
+ $$(call DependOnVariable, JDK_UNDER_TEST)
+ $$(call LogWarn, Generating $$(patsubst $$(OUTPUTDIR)/%, %, $$@))
+ $$(call MakeTargetDir)
+ $$(call ExecuteWithLog, $$@, \
+ $((COV_ENVIRONMENT) \
+ $$(FIXPATH) $$(JDK_UNDER_TEST)/bin/jaotc \
+ $$($1_JAOTC_OPTS) --output $$@ --module $$($1_MODULE) \
+ )
+ $$(call ExecuteWithLog, $$@.check, ( \
+ $$(FIXPATH) $$(JDK_UNDER_TEST)/bin/java \
+ $$($1_VM_OPTIONS) -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions \
+ -XX:+PrintAOT -XX:+UseAOTStrictLoading \
+ -XX:AOTLibrary=$$@ -version \
+ > $$@.verify-aot \
+ ))
+
+ $1_AOT_OPTIONS += -XX:+UnlockExperimentalVMOptions
+ $1_AOT_OPTIONS += -XX:AOTLibrary=$$($1_AOT_LIB)
+ $1_AOT_TARGETS += $$($1_AOT_LIB)
+endef
+
+################################################################################
+# Optionally create AOT libraries before running tests.
+# Note, this could not be done during JDK build time.
+################################################################################
+# Parameter 1 is the name of the rule.
+#
+# Remaining parameters are named arguments.
+# MODULES The modules to generate a library for
+# VM_OPTIONS List of JVM arguments to use when creating libraries
+#
+# After calling this, the following variables are defined
+# $1_AOT_OPTIONS List of all java options needed to use the AOT libraries
+# $1_AOT_TARGETS List of all targets that the test rule will need to depend on
+#
+SetupAot = $(NamedParamsMacroTemplate)
+define SetupAotBody
+ $$(info Running with AOTd libraries for $$($1_MODULES))
+ # Put aot libraries in a separate directory so they are not deleted between
+ # test runs and may be reused between make invocations.
+ $$(foreach m, $$($1_MODULES), \
+ $$(eval $$(call SetupAotModule, $1_$$m, \
+ MODULE := $$m, \
+ BIN := $$(TEST_SUPPORT_DIR)/aot/$1, \
+ VM_OPTIONS := $$($1_VM_OPTIONS), \
+ )) \
+ $$(eval $1_AOT_OPTIONS += $$($1_$$m_AOT_OPTIONS)) \
+ $$(eval $1_AOT_TARGETS += $$($1_$$m_AOT_TARGETS)) \
+ )
+endef
+
################################################################################
# Setup global test running parameters
################################################################################
@@ -192,6 +282,7 @@ endif
$(eval $(call SetTestOpt,VM_OPTIONS,JTREG))
$(eval $(call SetTestOpt,JAVA_OPTIONS,JTREG))
+$(eval $(call SetTestOpt,AOT_MODULES,JTREG))
$(eval $(call SetTestOpt,JOBS,JTREG))
$(eval $(call SetTestOpt,TIMEOUT_FACTOR,JTREG))
@@ -202,7 +293,7 @@ $(eval $(call ParseKeywordVariable, JTREG, \
TEST_MODE ASSERT VERBOSE RETAIN MAX_MEM RUN_PROBLEM_LISTS \
RETRY_COUNT REPEAT_COUNT MAX_OUTPUT $(CUSTOM_JTREG_SINGLE_KEYWORDS), \
STRING_KEYWORDS := OPTIONS JAVA_OPTIONS VM_OPTIONS KEYWORDS \
- EXTRA_PROBLEM_LISTS LAUNCHER_OPTIONS\
+ EXTRA_PROBLEM_LISTS AOT_MODULES LAUNCHER_OPTIONS\
$(CUSTOM_JTREG_STRING_KEYWORDS), \
))
@@ -306,10 +306,11 @@ endif
$(eval $(call SetTestOpt,VM_OPTIONS,GTEST))
$(eval $(call SetTestOpt,JAVA_OPTIONS,GTEST))
+$(eval $(call SetTestOpt,AOT_MODULES,GTEST))
$(eval $(call ParseKeywordVariable, GTEST, \
SINGLE_KEYWORDS := REPEAT, \
- STRING_KEYWORDS := OPTIONS VM_OPTIONS JAVA_OPTIONS, \
+ STRING_KEYWORDS := OPTIONS VM_OPTIONS JAVA_OPTIONS AOT_MODULES, \
))
ifneq ($(GTEST), )
@@ -499,7 +590,14 @@ define SetupRunGtestTestBody
$1_GTEST_REPEAT :=--gtest_repeat=$$(GTEST_REPEAT)
endif
- run-test-$1: pre-run-test
+ ifneq ($$(GTEST_AOT_MODULES), )
+ $$(eval $$(call SetupAot, $1, \
+ MODULES := $$(GTEST_AOT_MODULES), \
+ VM_OPTIONS := $$(GTEST_VM_OPTIONS) $$(GTEST_JAVA_OPTIONS), \
+ ))
+ endif
+
+ run-test-$1: pre-run-test $$($1_AOT_TARGETS)
$$(call LogWarn)
$$(call LogWarn, Running test '$$($1_TEST)')
$$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR))
@@ -510,7 +608,7 @@ define SetupRunGtestTestBody
--gtest_output=xml:$$($1_TEST_RESULTS_DIR)/gtest.xml \
--gtest_catch_exceptions=0 \
$$($1_GTEST_REPEAT) $$(GTEST_OPTIONS) $$(GTEST_VM_OPTIONS) \
- $$(GTEST_JAVA_OPTIONS) \
+ $$(GTEST_JAVA_OPTIONS) $$($1_AOT_OPTIONS) \
> >($(TEE) $$($1_TEST_RESULTS_DIR)/gtest.txt) \
&& $$(ECHO) $$$$? > $$($1_EXITCODE) \
|| $$(ECHO) $$$$? > $$($1_EXITCODE) \
@@ -874,6 +972,17 @@ define SetupRunJtregTestBody
JTREG_TIMEOUT_FACTOR ?= $$(JTREG_AUTO_TIMEOUT_FACTOR)
+ ifneq ($$(JTREG_AOT_MODULES), )
+ $$(eval $$(call SetupAot, $1, \
+ MODULES := $$(JTREG_AOT_MODULES), \
+ VM_OPTIONS := $$(JTREG_VM_OPTIONS) $$(JTREG_JAVA_OPTIONS), \
+ ))
+ endif
+
+ ifneq ($$($1_AOT_OPTIONS), )
+ $1_JTREG_BASIC_OPTIONS += -vmoptions:"$$($1_AOT_OPTIONS)"
+ endif
+
clean-outputdirs-$1:
$$(RM) -r $$($1_TEST_SUPPORT_DIR)
$$(RM) -r $$($1_TEST_RESULTS_DIR)
@@ -921,7 +1030,7 @@ define SetupRunJtregTestBody
done
endif
- run-test-$1: pre-run-test clean-outputdirs-$1
+ run-test-$1: pre-run-test clean-outputdirs-$1 $$($1_AOT_TARGETS)
$$(call LogWarn)
$$(call LogWarn, Running test '$$($1_TEST)')
$$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR) \
diff --git a/make/RunTestsPrebuilt.gmk b/make/RunTestsPrebuilt.gmk
index 7c1c55b20..c5f4453cd 100644
--- a/make/RunTestsPrebuilt.gmk
+++ b/make/RunTestsPrebuilt.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -230,6 +230,25 @@ ifeq ($(MEMORY_SIZE), )
MEMORY_SIZE := 1024
endif
+# Setup LD for AOT support
+ifneq ($(DEVKIT_HOME), )
+ ifeq ($(OPENJDK_TARGET_OS), windows)
+ LD_JAOTC := $(DEVKIT_HOME)/VC/bin/x64/link.exe
+ LIBRARY_PREFIX :=
+ SHARED_LIBRARY_SUFFIX := .dll
+ else ifeq ($(OPENJDK_TARGET_OS), linux)
+ LD_JAOTC := $(DEVKIT_HOME)/bin/ld
+ LIBRARY_PREFIX := lib
+ SHARED_LIBRARY_SUFFIX := .so
+ else ifeq ($(OPENJDK_TARGET_OS), macosx)
+ LD_JAOTC := $(DEVKIT_HOME)/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld
+ LIBRARY_PREFIX := lib
+ SHARED_LIBRARY_SUFFIX := .dylib
+ endif
+else
+ LD := ld
+endif
+
ifneq ($(wildcard $(JDK_IMAGE_DIR)/template.xml), )
TEST_OPTS_JCOV := true
JCOV_IMAGE_DIR := $(JDK_IMAGE_DIR)
@@ -276,6 +295,9 @@ $(call CreateNewSpec, $(NEW_SPEC), \
OPENJDK_TARGET_CPU_ENDIAN := $(OPENJDK_TARGET_CPU_ENDIAN), \
NUM_CORES := $(NUM_CORES), \
MEMORY_SIZE := $(MEMORY_SIZE), \
+ LD_JAOTC := $(LD_JAOTC), \
+ LIBRARY_PREFIX := $(LIBRARY_PREFIX), \
+ SHARED_LIBRARY_SUFFIX := $(SHARED_LIBRARY_SUFFIX), \
include $(TOPDIR)/make/RunTestsPrebuiltSpec.gmk, \
TEST_OPTS_JCOV := $(TEST_OPTS_JCOV), \
$(CUSTOM_NEW_SPEC_LINE), \
diff --git a/make/autoconf/jvm-features.m4 b/make/autoconf/jvm-features.m4
index 86dec71d0..6e81c84d9 100644
--- a/make/autoconf/jvm-features.m4
+++ b/make/autoconf/jvm-features.m4
@@ -44,7 +44,7 @@
m4_define(jvm_features_valid, m4_normalize( \
ifdef([custom_jvm_features_valid], custom_jvm_features_valid) \
\
- cds compiler1 compiler2 dtrace epsilongc g1gc graal jbooster jfr jni-check \
+ aot cds compiler1 compiler2 dtrace epsilongc g1gc graal jbooster jfr jni-check \
jvmci jvmti link-time-opt management minimal nmt opt-size parallelgc \
serialgc services shenandoahgc static-build vm-structs zero zgc \
))
@@ -55,6 +55,7 @@ m4_define(jvm_features_deprecated, m4_normalize(
))
# Feature descriptions
+m4_define(jvm_feature_desc_aot, [enable ahead of time compilation (AOT)])
m4_define(jvm_feature_desc_cds, [enable class data sharing (CDS)])
m4_define(jvm_feature_desc_compiler1, [enable hotspot compiler C1])
m4_define(jvm_feature_desc_compiler2, [enable hotspot compiler C2])
@@ -94,6 +95,7 @@ AC_DEFUN_ONCE([JVM_FEATURES_PARSE_OPTIONS],
# For historical reasons, some jvm features have their own, shorter names.
# Keep those as aliases for the --enable-jvm-feature-* style arguments.
+ UTIL_ALIASED_ARG_ENABLE(aot, --enable-jvm-feature-aot)
UTIL_ALIASED_ARG_ENABLE(cds, --enable-jvm-feature-cds)
UTIL_ALIASED_ARG_ENABLE(dtrace, --enable-jvm-feature-dtrace)
@@ -145,9 +147,9 @@ AC_DEFUN_ONCE([JVM_FEATURES_PARSE_OPTIONS],
if test "x$FEATURE_SHELL" = xyes; then
JVM_FEATURES_ENABLED="$JVM_FEATURES_ENABLED FEATURE"
- # Attach graal feature
+ # Attach aot and graal feature
if test FEATURE = jbooster; then
- JVM_FEATURES_ENABLED="$JVM_FEATURES_ENABLED graal"
+ JVM_FEATURES_ENABLED="$JVM_FEATURES_ENABLED aot graal"
fi
elif test "x$FEATURE_SHELL" = xno; then
JVM_FEATURES_DISABLED="$JVM_FEATURES_DISABLED FEATURE"
@@ -232,6 +234,34 @@ AC_DEFUN([JVM_FEATURES_CHECK_AVAILABILITY],
fi
])
+###############################################################################
+# Check if the feature 'aot' is available on this platform.
+#
+AC_DEFUN_ONCE([JVM_FEATURES_CHECK_AOT],
+[
+ JVM_FEATURES_CHECK_AVAILABILITY(aot, [
+ AC_MSG_CHECKING([if platform is supported by AOT])
+ # AOT is only available where JVMCI is available since it requires JVMCI.
+ if test "x$OPENJDK_TARGET_CPU" = "xx86_64"; then
+ AC_MSG_RESULT([yes])
+ elif test "x$OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU" = "xlinux-aarch64"; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no, $OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU])
+ AVAILABLE=false
+ fi
+
+ AC_MSG_CHECKING([if AOT source code is present])
+ if test -e "${TOPDIR}/src/jdk.internal.vm.compiler" && \
+ test -e "${TOPDIR}/src/jdk.aot"; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no, missing src/jdk.internal.vm.compiler or src/jdk.aot])
+ AVAILABLE=false
+ fi
+ ])
+])
+
###############################################################################
# Check if the feature 'cds' is available on this platform.
#
@@ -444,6 +474,7 @@ AC_DEFUN_ONCE([JVM_FEATURES_PREPARE_PLATFORM],
# The checks below should add unavailable features to
# JVM_FEATURES_PLATFORM_UNAVAILABLE.
+ JVM_FEATURES_CHECK_AOT
JVM_FEATURES_CHECK_CDS
JVM_FEATURES_CHECK_DTRACE
JVM_FEATURES_CHECK_GRAAL
@@ -480,7 +511,7 @@ AC_DEFUN([JVM_FEATURES_PREPARE_VARIANT],
elif test "x$variant" = "xcore"; then
JVM_FEATURES_VARIANT_UNAVAILABLE="cds jbooster minimal zero"
elif test "x$variant" = "xzero"; then
- JVM_FEATURES_VARIANT_UNAVAILABLE="cds compiler1 compiler2 \
+ JVM_FEATURES_VARIANT_UNAVAILABLE="aot cds compiler1 compiler2 \
graal jbooster jvmci minimal zgc"
else
JVM_FEATURES_VARIANT_UNAVAILABLE="minimal zero"
@@ -488,9 +519,9 @@ AC_DEFUN([JVM_FEATURES_PREPARE_VARIANT],
# Check which features should be off by default for this JVM variant.
if test "x$variant" = "xclient"; then
- JVM_FEATURES_VARIANT_FILTER="compiler2 graal jbooster jvmci link-time-opt opt-size"
+ JVM_FEATURES_VARIANT_FILTER="aot compiler2 graal jbooster jvmci link-time-opt opt-size"
elif test "x$variant" = "xminimal"; then
- JVM_FEATURES_VARIANT_FILTER="cds compiler2 dtrace epsilongc g1gc graal jbooster \
+ JVM_FEATURES_VARIANT_FILTER="aot cds compiler2 dtrace epsilongc g1gc graal jbooster \
jfr jni-check jvmci jvmti management nmt parallelgc services \
shenandoahgc vm-structs zgc"
if test "x$OPENJDK_TARGET_CPU" = xarm ; then
@@ -501,12 +532,12 @@ AC_DEFUN([JVM_FEATURES_PREPARE_VARIANT],
link-time-opt"
fi
elif test "x$variant" = "xcore"; then
- JVM_FEATURES_VARIANT_FILTER="compiler1 compiler2 graal jbooster jvmci \
+ JVM_FEATURES_VARIANT_FILTER="aot compiler1 compiler2 graal jbooster jvmci \
link-time-opt opt-size"
elif test "x$variant" = "xzero"; then
- JVM_FEATURES_VARIANT_FILTER="graal jbooster jfr link-time-opt opt-size"
+ JVM_FEATURES_VARIANT_FILTER="aot graal jbooster jfr link-time-opt opt-size"
else
- JVM_FEATURES_VARIANT_FILTER="graal jbooster link-time-opt opt-size"
+ JVM_FEATURES_VARIANT_FILTER="aot graal jbooster link-time-opt opt-size"
fi
])
@@ -578,14 +609,18 @@ AC_DEFUN([JVM_FEATURES_VERIFY],
variant=$1
# Verify that dependencies are met for inter-feature relations.
+ if JVM_FEATURES_IS_ACTIVE(aot) && ! JVM_FEATURES_IS_ACTIVE(graal); then
+ AC_MSG_ERROR([Specified JVM feature 'aot' requires feature 'graal' for variant '$variant'])
+ fi
+
if JVM_FEATURES_IS_ACTIVE(graal) && ! JVM_FEATURES_IS_ACTIVE(jvmci); then
AC_MSG_ERROR([Specified JVM feature 'graal' requires feature 'jvmci' for variant '$variant'])
fi
# FIX ME: Fill up the dependencies with aot module
if JVM_FEATURES_IS_ACTIVE(jbooster) && ! (JVM_FEATURES_IS_ACTIVE(cds) && \
- JVM_FEATURES_IS_ACTIVE(graal)); then
- AC_MSG_ERROR([Specified JVM feature 'jbooster' requires feature 'cds' and 'graal' for variant '$variant'])
+ JVM_FEATURES_IS_ACTIVE(graal) && JVM_FEATURES_IS_ACTIVE(aot)); then
+ AC_MSG_ERROR([Specified JVM feature 'jbooster' requires feature 'cds', 'aot' and 'graal' for variant '$variant'])
fi
if JVM_FEATURES_IS_ACTIVE(jvmci) && ! (JVM_FEATURES_IS_ACTIVE(compiler1) || \
@@ -603,6 +638,9 @@ AC_DEFUN([JVM_FEATURES_VERIFY],
# For backwards compatibility, disable a feature "globally" if one variant
# is missing the feature.
+ if JVM_FEATURES_IS_ACTIVE(aot); then
+ ENABLE_AOT="true"
+ fi
if ! JVM_FEATURES_IS_ACTIVE(cds); then
ENABLE_CDS="false"
fi
@@ -639,6 +677,7 @@ AC_DEFUN_ONCE([JVM_FEATURES_SETUP],
# For backwards compatibility, tentatively enable these features "globally",
# and disable them in JVM_FEATURES_VERIFY if a variant is found that are
# missing any of them.
+ ENABLE_AOT="false"
ENABLE_CDS="true"
INCLUDE_GRAAL="false"
INCLUDE_JVMCI="true"
@@ -679,6 +718,7 @@ AC_DEFUN_ONCE([JVM_FEATURES_SETUP],
AC_SUBST(JVM_FEATURES_zero)
AC_SUBST(JVM_FEATURES_custom)
+ AC_SUBST(ENABLE_AOT)
AC_SUBST(INCLUDE_GRAAL)
AC_SUBST(INCLUDE_JVMCI)
AC_SUBST(INCLUDE_COMPILER2)
diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in
index 0842774cf..e3f43ebf0 100644
--- a/make/autoconf/spec.gmk.in
+++ b/make/autoconf/spec.gmk.in
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -533,6 +533,9 @@ CPP := @CPP@
# The linker can be gcc or ld on unix systems, or link.exe on windows systems.
LD := @LD@
+# Linker used by the jaotc tool for AOT compilation.
+LD_JAOTC:=@LD_JAOTC@
+
# Xcode SDK path
SDKROOT:=@SDKROOT@
@@ -777,6 +780,7 @@ TAR_SUPPORTS_TRANSFORM:=@TAR_SUPPORTS_TRANSFORM@
# Build setup
ENABLE_KAE:=@ENABLE_KAE@
+ENABLE_AOT:=@ENABLE_AOT@
USE_EXTERNAL_LIBJPEG:=@USE_EXTERNAL_LIBJPEG@
USE_EXTERNAL_LIBGIF:=@USE_EXTERNAL_LIBGIF@
USE_EXTERNAL_LIBZ:=@USE_EXTERNAL_LIBZ@
diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4
index 8105ce9e8..3a83873b9 100644
--- a/make/autoconf/toolchain.m4
+++ b/make/autoconf/toolchain.m4
@@ -674,12 +674,18 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETECT_TOOLCHAIN_CORE],
UTIL_LOOKUP_TOOLCHAIN_PROGS(LD, link)
TOOLCHAIN_VERIFY_LINK_BINARY(LD)
LDCXX="$LD"
+ # jaotc being a windows program expects the linker to be supplied with exe suffix.but without
+ # fixpath
+ LD_JAOTC="${LD##$FIXPATH }"
else
# All other toolchains use the compiler to link.
LD="$CC"
LDCXX="$CXX"
+ # jaotc expects 'ld' as the linker rather than the compiler.
+ UTIL_LOOKUP_TOOLCHAIN_PROGS(LD_JAOTC, ld)
fi
AC_SUBST(LD)
+ AC_SUBST(LD_JAOTC)
# FIXME: it should be CXXLD, according to standard (cf CXXCPP)
AC_SUBST(LDCXX)
diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk
index 20d224d1e..ebb5756e3 100644
--- a/make/common/Modules.gmk
+++ b/make/common/Modules.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -70,6 +70,11 @@ ifeq ($(INCLUDE_GRAAL), false)
MODULES_FILTER += jdk.internal.vm.compiler.management
endif
+# Filter out aot specific modules if aot is disabled
+ifeq ($(ENABLE_AOT), false)
+ MODULES_FILTER += jdk.aot
+endif
+
# Filter out jbooster specific modules if jbooster is disabled
ifeq ($(INCLUDE_JBOOSTER), false)
MODULES_FILTER += jdk.jbooster
diff --git a/make/conf/build-module-sets.conf b/make/conf/build-module-sets.conf
index d6f1c25cf..853a29012 100644
--- a/make/conf/build-module-sets.conf
+++ b/make/conf/build-module-sets.conf
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -44,6 +44,7 @@ LANGTOOLS_MODULES= \
# These models require buildtools-hotspot to process for gensrc
HOTSPOT_MODULES= \
+ jdk.aot \
jdk.hotspot.agent \
jdk.internal.vm.ci \
jdk.internal.vm.compiler \
diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js
index 17cf101db..92bcb1b72 100644
--- a/make/conf/jib-profiles.js
+++ b/make/conf/jib-profiles.js
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -252,6 +252,7 @@ var getJibProfilesCommon = function (input, data) {
configure_args: concat("--enable-jtreg-failure-handler",
"--with-exclude-translations=es,fr,it,ko,pt_BR,sv,ca,tr,cs,sk,ja_JP_A,ja_JP_HA,ja_JP_HI,ja_JP_I,zh_TW,zh_HK",
"--disable-manpages",
+ "--disable-jvm-feature-aot",
"--disable-jvm-feature-graal",
"--disable-jvm-feature-shenandoahgc",
versionArgs(input, common))
diff --git a/make/conf/module-loader-map.conf b/make/conf/module-loader-map.conf
index 051ca4dc8..847e01ade 100644
--- a/make/conf/module-loader-map.conf
+++ b/make/conf/module-loader-map.conf
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -61,6 +61,7 @@ BOOT_MODULES= \
# should carefully be considered if it should be upgradeable or not.
UPGRADEABLE_PLATFORM_MODULES= \
java.compiler \
+ jdk.aot \
jdk.internal.vm.compiler \
jdk.internal.vm.compiler.management \
#
diff --git a/make/hotspot/lib/JvmFeatures.gmk b/make/hotspot/lib/JvmFeatures.gmk
index 0c83ec254..ff5b243ae 100644
--- a/make/hotspot/lib/JvmFeatures.gmk
+++ b/make/hotspot/lib/JvmFeatures.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -129,6 +129,14 @@ ifneq ($(call check-jvm-feature, nmt), true)
memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp threadStackTracker.cpp
endif
+ifneq ($(call check-jvm-feature, aot), true)
+ JVM_CFLAGS_FEATURES += -DINCLUDE_AOT=0
+ JVM_EXCLUDE_FILES += \
+ compiledIC_aot_x86_64.cpp compiledIC_aot_aarch64.cpp \
+ compilerRuntime.cpp aotCodeHeap.cpp aotCompiledMethod.cpp \
+ aotLoader.cpp compiledIC_aot.cpp
+endif
+
ifneq ($(call check-jvm-feature, g1gc), true)
JVM_CFLAGS_FEATURES += -DINCLUDE_G1GC=0
JVM_EXCLUDE_PATTERNS += gc/g1
diff --git a/make/ide/visualstudio/hotspot/CreateVSProject.gmk b/make/ide/visualstudio/hotspot/CreateVSProject.gmk
index e7a1dcc5b..2e2b95d2f 100644
--- a/make/ide/visualstudio/hotspot/CreateVSProject.gmk
+++ b/make/ide/visualstudio/hotspot/CreateVSProject.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -111,6 +111,7 @@ ifeq ($(call isTargetOs, windows), true)
-relativeSrcInclude hotspot \
-hidePath .hg \
-hidePath .jcheck \
+ -hidePath jdk.aot \
-hidePath jdk.hotspot.agent \
-hidePath jdk.internal.vm.ci \
-hidePath jdk.internal.vm.compiler \
diff --git a/make/modules/jdk.aot/Java.gmk b/make/modules/jdk.aot/Java.gmk
new file mode 100644
index 000000000..9fcbaed43
--- /dev/null
+++ b/make/modules/jdk.aot/Java.gmk
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# -parameters provides method's parameters information in class file,
+# JVMCI compilers make use of that information for various sanity checks.
+# Don't use Indy strings concatenation to have good JAOTC startup performance.
+# The exports are needed since JVMCI is dynamically exported (see
+# jdk.vm.ci.services.internal.ReflectionAccessJDK::openJVMCITo).
+
+JAVAC_FLAGS += -parameters -XDstringConcat=inline \
+ --add-exports jdk.internal.vm.ci/jdk.vm.ci.aarch64=jdk.internal.vm.compiler,jdk.aot \
+ --add-exports jdk.internal.vm.ci/jdk.vm.ci.amd64=jdk.internal.vm.compiler,jdk.aot \
+ --add-exports jdk.internal.vm.ci/jdk.vm.ci.code=jdk.internal.vm.compiler,jdk.aot \
+ --add-exports jdk.internal.vm.ci/jdk.vm.ci.code.site=jdk.internal.vm.compiler,jdk.aot \
+ --add-exports jdk.internal.vm.ci/jdk.vm.ci.code.stack=jdk.internal.vm.compiler,jdk.aot \
+ --add-exports jdk.internal.vm.ci/jdk.vm.ci.common=jdk.internal.vm.compiler,jdk.aot \
+ --add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot=jdk.internal.vm.compiler,jdk.aot \
+ --add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.aarch64=jdk.internal.vm.compiler,jdk.aot \
+ --add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.amd64=jdk.internal.vm.compiler,jdk.aot \
+ --add-exports jdk.internal.vm.ci/jdk.vm.ci.meta=jdk.internal.vm.compiler,jdk.aot \
+ --add-exports jdk.internal.vm.ci/jdk.vm.ci.runtime=jdk.internal.vm.compiler,jdk.aot \
+ #
+
+EXCLUDES += \
+ jdk.tools.jaotc.test
+ #
+
+## WORKAROUND jdk.aot source structure issue
+AOT_MODULESOURCEPATH := $(MODULESOURCEPATH) \
+ $(subst /$(MODULE)/,/*/, $(filter-out %processor/src, \
+ $(wildcard $(TOPDIR)/src/$(MODULE)/share/classes/*/src)))
+MODULESOURCEPATH := $(call PathList, $(AOT_MODULESOURCEPATH))
diff --git a/make/modules/jdk.aot/Launcher.gmk b/make/modules/jdk.aot/Launcher.gmk
new file mode 100644
index 000000000..4b7e843b1
--- /dev/null
+++ b/make/modules/jdk.aot/Launcher.gmk
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include LauncherCommon.gmk
+
+# The JVMCI exports are needed since JVMCI is normally dynamically exported
+# (see jdk.vm.ci.services.internal.ReflectionAccessJDK::openJVMCITo).
+
+$(eval $(call SetupBuildLauncher, jaotc, \
+ MAIN_CLASS := jdk.tools.jaotc.Main, \
+ EXTRA_JAVA_ARGS := -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI \
+ --add-exports=jdk.internal.vm.ci/jdk.vm.ci.aarch64=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
+ --add-exports=jdk.internal.vm.ci/jdk.vm.ci.amd64=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
+ --add-exports=jdk.internal.vm.ci/jdk.vm.ci.code=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
+ --add-exports=jdk.internal.vm.ci/jdk.vm.ci.code.site=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
+ --add-exports=jdk.internal.vm.ci/jdk.vm.ci.code.stack=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
+ --add-exports=jdk.internal.vm.ci/jdk.vm.ci.common=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
+ --add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
+ , \
+ JAVA_ARGS := --add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot.aarch64=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
+ --add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot.amd64=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
+ --add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot.aarch64=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
+ --add-exports=jdk.internal.vm.ci/jdk.vm.ci.meta=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
+ --add-exports=jdk.internal.vm.ci/jdk.vm.ci.runtime=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
+ -XX:+UnlockExperimentalVMOptions -XX:+UseAOT \
+ -XX:+CalculateClassFingerprint \
+ -Djvmci.UseProfilingInformation=false \
+ -Dgraal.UseExceptionProbability=false \
+ -Djvmci.Compiler=graal \
+ --add-modules ALL-DEFAULT \
+ , \
+))
diff --git a/make/modules/jdk.internal.vm.compiler/Java.gmk b/make/modules/jdk.internal.vm.compiler/Java.gmk
index c2b92597a..3b4672956 100644
--- a/make/modules/jdk.internal.vm.compiler/Java.gmk
+++ b/make/modules/jdk.internal.vm.compiler/Java.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,7 @@ JAVAC_FLAGS += -parameters -XDstringConcat=inline \
EXCLUDES += \
jdk.internal.vm.compiler.collections.test \
+ jdk.tools.jaotc.test \
org.graalvm.compiler.api.directives.test \
org.graalvm.compiler.api.test \
org.graalvm.compiler.asm.aarch64.test \
diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad
index f28cc9cd6..350e4cad0 100644
--- a/src/hotspot/cpu/aarch64/aarch64.ad
+++ b/src/hotspot/cpu/aarch64/aarch64.ad
@@ -1,6 +1,6 @@
//
-// Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
-// Copyright (c) 2014, 2021, Red Hat, Inc. All rights reserved.
+// Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2014, 2023, Red Hat, Inc. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// This code is free software; you can redistribute it and/or modify it
@@ -1360,7 +1360,7 @@ source %{
// r27 is not allocatable when compressed oops is on and heapbase is not
// zero, compressed klass pointers doesn't use r27 after JDK-8234794
- if (UseCompressedOops && (CompressedOops::ptrs_base() != NULL)) {
+ if (UseCompressedOops && (CompressedOops::ptrs_base() != NULL || UseAOT)) {
_NO_SPECIAL_REG32_mask.Remove(OptoReg::as_OptoReg(r27->as_VMReg()));
_NO_SPECIAL_REG_mask.SUBTRACT(_HEAPBASE_REG_mask);
_NO_SPECIAL_PTR_REG_mask.SUBTRACT(_HEAPBASE_REG_mask);
diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp
index d39f57087..2bbfe91ee 100644
--- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -75,6 +75,7 @@ friend class ArrayCopyStub;
static int _call_stub_size;
enum {
+ _call_aot_stub_size = 0,
_exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175),
_deopt_handler_size = 7 * NativeInstruction::instruction_size
};
diff --git a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp
index 209f50efe..5dbb59a1c 100644
--- a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp
@@ -1384,7 +1384,7 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result,
// membar it's possible for a simple Dekker test to fail if loads
// use LD;DMB but stores use STLR. This can happen if C2 compiles
// the stores in one method and C1 compiles the loads in another.
- if (!CompilerConfig::is_c1_only_no_jvmci()) {
+ if (!CompilerConfig::is_c1_only_no_aot_or_jvmci()) {
__ membar();
}
__ volatile_load_mem_reg(address, result, info);
diff --git a/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp b/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp
index c6a9d8387..dd8cf4981 100644
--- a/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2014, 2018, Red Hat Inc. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -60,6 +60,15 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark)
// static stub relocation stores the instruction address of the call
__ relocate(static_stub_Relocation::spec(mark));
+#if INCLUDE_AOT
+ // Don't create a Metadata reloc if we're generating immutable PIC.
+ if (cbuf.immutable_PIC()) {
+ __ movptr(rmethod, 0);
+ __ movptr(rscratch1, 0);
+ __ br(rscratch1);
+
+ } else
+#endif
{
__ emit_static_call_stub();
}
@@ -92,8 +101,63 @@ int CompiledStaticCall::reloc_to_interp_stub() {
return 4; // 3 in emit_to_interp_stub + 1 in emit_call
}
+#if INCLUDE_AOT
+#define __ _masm.
+void CompiledStaticCall::emit_to_aot_stub(CodeBuffer &cbuf, address mark) {
+ if (!UseAOT) {
+ return;
+ }
+ // Stub is fixed up when the corresponding call is converted from
+ // calling compiled code to calling aot code.
+ // mov r, imm64_aot_code_address
+ // jmp r
+
+ if (mark == NULL) {
+ mark = cbuf.insts_mark(); // Get mark within main instrs section.
+ }
+
+ // Note that the code buffer's insts_mark is always relative to insts.
+ // That's why we must use the macroassembler to generate a stub.
+ MacroAssembler _masm(&cbuf);
+
+ address base =
+ __ start_a_stub(to_aot_stub_size());
+ guarantee(base != NULL, "out of space");
+
+ // Static stub relocation stores the instruction address of the call.
+ __ relocate(static_stub_Relocation::spec(mark, true /* is_aot */));
+ // Load destination AOT code address.
+ __ movptr(rscratch1, 0); // address is zapped till fixup time.
+ // This is recognized as unresolved by relocs/nativeinst/ic code.
+ __ br(rscratch1);
+
+ assert(__ pc() - base <= to_aot_stub_size(), "wrong stub size");
+
+ // Update current stubs pointer and restore insts_end.
+ __ end_a_stub();
+}
+#undef __
+
+int CompiledStaticCall::to_aot_stub_size() {
+ if (UseAOT) {
+ return 5 * 4; // movz; movk; movk; movk; br
+ } else {
+ return 0;
+ }
+}
+
+// Relocation entries for call stub, compiled java to aot.
+int CompiledStaticCall::reloc_to_aot_stub() {
+ if (UseAOT) {
+ return 5 * 4; // movz; movk; movk; movk; br
+ } else {
+ return 0;
+ }
+}
+#endif // INCLUDE_AOT
+
void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
- address stub = find_stub();
+ address stub = find_stub(false /* is_aot */);
guarantee(stub != NULL, "stub not found");
if (TraceICs) {
@@ -129,8 +193,10 @@ void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_
NativeMovConstReg* method_holder
= nativeMovConstReg_at(stub + NativeInstruction::instruction_size);
method_holder->set_data(0);
- NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
- jump->set_jump_destination((address)-1);
+ if (!static_stub->is_aot()) {
+ NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
+ jump->set_jump_destination((address)-1);
+ }
}
//-----------------------------------------------------------------------------
@@ -143,7 +209,7 @@ void CompiledDirectStaticCall::verify() {
_call->verify_alignment();
// Verify stub.
- address stub = find_stub();
+ address stub = find_stub(false /* is_aot */);
assert(stub != NULL, "no stub found for static call");
// Creation also verifies the object.
NativeMovConstReg* method_holder
diff --git a/src/hotspot/cpu/aarch64/compiledIC_aot_aarch64.cpp b/src/hotspot/cpu/aarch64/compiledIC_aot_aarch64.cpp
new file mode 100644
index 000000000..bfd81cc96
--- /dev/null
+++ b/src/hotspot/cpu/aarch64/compiledIC_aot_aarch64.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2023, Red Hat Inc. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "aot/compiledIC_aot.hpp"
+#include "code/codeCache.hpp"
+#include "memory/resourceArea.hpp"
+#include "memory/universe.hpp"
+
+void CompiledDirectStaticCall::set_to_far(const methodHandle& callee, address entry) {
+ if (TraceICs) {
+ ResourceMark rm;
+ tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_far %s",
+ p2i(instruction_address()),
+ callee->name_and_sig_as_C_string());
+ }
+
+ set_destination_mt_safe(entry);
+}
+
+void CompiledPltStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
+ address stub = find_stub();
+ guarantee(stub != NULL, "stub not found");
+ if (TraceICs) {
+ ResourceMark rm;
+ tty->print_cr("CompiledPltStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
+ p2i(instruction_address()),
+ callee->name_and_sig_as_C_string());
+ }
+
+ // Creation also verifies the object.
+ NativeLoadGot* method_loader = nativeLoadGot_at(stub);
+ NativeGotJump* jump = nativeGotJump_at(method_loader->next_instruction_address());
+
+ intptr_t data = method_loader->data();
+ address destination = jump->destination();
+ assert(data == 0 || data == (intptr_t)callee(),
+ "a) MT-unsafe modification of inline cache");
+ assert(destination == (address)Universe::non_oop_word()
+ || destination == entry,
+ "b) MT-unsafe modification of inline cache");
+
+ // Update stub.
+ method_loader->set_data((intptr_t)callee());
+ jump->set_jump_destination(entry);
+
+ // Update jump to call.
+ set_destination_mt_safe(stub);
+}
+
+#ifdef NEVER_CALLED
+void CompiledPltStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
+ // Reset stub.
+ address stub = static_stub->addr();
+ assert(stub != NULL, "stub not found");
+ assert(CompiledICLocker::is_safe(stub), "mt unsafe call");
+ // Creation also verifies the object.
+ NativeLoadGot* method_loader = nativeLoadGot_at(stub);
+ NativeGotJump* jump = nativeGotJump_at(method_loader->next_instruction_address());
+ method_loader->set_data(0);
+ jump->set_jump_destination((address)-1);
+}
+#endif
+
+#ifndef PRODUCT
+void CompiledPltStaticCall::verify() {
+ // Verify call.
+ _call->verify();
+
+#ifdef ASSERT
+ CodeBlob *cb = CodeCache::find_blob_unsafe((address) _call);
+ assert(cb && cb->is_aot(), "CompiledPltStaticCall can only be used on AOTCompiledMethod");
+#endif
+
+ // Verify stub.
+ address stub = find_stub();
+ assert(stub != NULL, "no stub found for static call");
+ // Creation also verifies the object.
+ NativeLoadGot* method_loader = nativeLoadGot_at(stub);
+ NativeGotJump* jump = nativeGotJump_at(method_loader->next_instruction_address());
+ // Verify state.
+ assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check");
+}
+#endif // !PRODUCT
diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp
index a56b13264..3c01c29e0 100644
--- a/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved.
+ * Copyright (c) 2018, 2023, Red Hat, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -51,7 +51,7 @@ void LIR_OpShenandoahCompareAndSwap::emit_code(LIR_Assembler* masm) {
ShenandoahBarrierSet::assembler()->cmpxchg_oop(masm->masm(), addr, cmpval, newval, /*acquire*/ true, /*release*/ true, /*is_cae*/ false, result);
- if (CompilerConfig::is_c1_only_no_jvmci()) {
+ if (CompilerConfig::is_c1_only_no_aot_or_jvmci()) {
// The membar here is necessary to prevent reordering between the
// release store in the CAS above and a subsequent volatile load.
// However for tiered compilation C1 inserts a full barrier before
diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
index 5e8cd1b37..9eb05d8c3 100644
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1083,7 +1083,7 @@ public:
address trampoline_call(Address entry, CodeBuffer* cbuf = NULL);
static bool far_branches() {
- return ReservedCodeCacheSize > branch_range;
+ return ReservedCodeCacheSize > branch_range || UseAOT;
}
// Jumps that can reach anywhere in the code cache.
diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp
index c75c65f66..90c36a115 100644
--- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -496,9 +496,16 @@ bool NativeInstruction::is_stop() {
void NativeJump::patch_verified_entry(address entry, address verified_entry, address dest) {
assert(dest == SharedRuntime::get_handle_wrong_method_stub(), "expected fixed destination of patch");
- assert(nativeInstruction_at(verified_entry)->is_jump_or_nop()
- || nativeInstruction_at(verified_entry)->is_sigill_zombie_not_entrant(),
- "Aarch64 cannot replace non-jump with jump");
+
+#ifdef ASSERT
+ // This may be the temporary nmethod generated while we're AOT
+ // compiling. Such an nmethod doesn't begin with a NOP but with an ADRP.
+ if (! (CalculateClassFingerprint && UseAOT && is_adrp_at(verified_entry))) {
+ assert(nativeInstruction_at(verified_entry)->is_jump_or_nop()
+ || nativeInstruction_at(verified_entry)->is_sigill_zombie_not_entrant(),
+ "Aarch64 cannot replace non-jump with jump");
+ }
+#endif
// Patch this nmethod atomically.
if (Assembler::reachable_from_branch_at(verified_entry, dest)) {
diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp
index 243bf6c68..60dc3be3a 100644
--- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2014, 2108, Red Hat Inc. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -235,6 +235,16 @@ public:
return is_call_at(return_address - NativeCall::return_address_offset);
}
+#if INCLUDE_AOT
+ // Return true iff a call from instr to target is out of range.
+ // Used for calls from JIT- to AOT-compiled code.
+ static bool is_far_call(address instr, address target) {
+ // On AArch64 we use trampolines which can reach anywhere in the
+ // address space, so calls are never out of range.
+ return false;
+ }
+#endif
+
// MT-safe patching of a call instruction.
static void insert(address code_pos, address entry);
diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
index 83e9be0b0..7ea60b273 100644
--- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved.
- * Copyright (c) 2021, Azul Systems, Inc. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Red Hat Inc. All rights reserved.
+ * Copyright (c) 2021, 2023, Azul Systems, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -594,7 +594,7 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
__ ldr(rscratch1, Address(rmethod, in_bytes(Method::from_compiled_offset())));
#if INCLUDE_JVMCI
- if (EnableJVMCI) {
+ if (EnableJVMCI || UseAOT) {
// check if this call should be routed towards a specific entry point
__ ldr(rscratch2, Address(rthread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())));
Label no_alternative_target;
@@ -2179,7 +2179,7 @@ void SharedRuntime::generate_deopt_blob() {
// Setup code generation tools
int pad = 0;
#if INCLUDE_JVMCI
- if (EnableJVMCI) {
+ if (EnableJVMCI || UseAOT) {
pad += 512; // Increase the buffer size when compiling for JVMCI
}
#endif
@@ -2254,7 +2254,7 @@ void SharedRuntime::generate_deopt_blob() {
int implicit_exception_uncommon_trap_offset = 0;
int uncommon_trap_offset = 0;
- if (EnableJVMCI) {
+ if (EnableJVMCI || UseAOT) {
implicit_exception_uncommon_trap_offset = __ pc() - start;
__ ldr(lr, Address(rthread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset())));
@@ -2379,7 +2379,7 @@ void SharedRuntime::generate_deopt_blob() {
__ reset_last_Java_frame(false);
#if INCLUDE_JVMCI
- if (EnableJVMCI) {
+ if (EnableJVMCI || UseAOT) {
__ bind(after_fetch_unroll_info_call);
}
#endif
@@ -2542,7 +2542,7 @@ void SharedRuntime::generate_deopt_blob() {
_deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words);
_deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
#if INCLUDE_JVMCI
- if (EnableJVMCI) {
+ if (EnableJVMCI || UseAOT) {
_deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset);
_deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset);
}
diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp
index e20cffd57..8482dc73c 100644
--- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -502,7 +502,7 @@ address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state,
#if INCLUDE_JVMCI
// Check if we need to take lock at entry of synchronized method. This can
// only occur on method entry so emit it only for vtos with step 0.
- if (EnableJVMCI && state == vtos && step == 0) {
+ if ((EnableJVMCI || UseAOT) && state == vtos && step == 0) {
Label L;
__ ldrb(rscratch1, Address(rthread, JavaThread::pending_monitorenter_offset()));
__ cbz(rscratch1, L);
diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
index 4666b42b9..8d573760e 100644
--- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2014, Red Hat Inc. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -2413,7 +2413,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr
// membar it's possible for a simple Dekker test to fail if loads
// use LDR;DMB but stores use STLR. This can happen if C2 compiles
// the stores in one method and we interpret the loads in another.
- if (!CompilerConfig::is_c1_or_interpreter_only_no_jvmci()){
+ if (!CompilerConfig::is_c1_or_interpreter_only_no_aot_or_jvmci()){
Label notVolatile;
__ tbz(raw_flags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
__ membar(MacroAssembler::AnyAny);
@@ -3016,7 +3016,7 @@ void TemplateTable::fast_accessfield(TosState state)
// membar it's possible for a simple Dekker test to fail if loads
// use LDR;DMB but stores use STLR. This can happen if C2 compiles
// the stores in one method and we interpret the loads in another.
- if (!CompilerConfig::is_c1_or_interpreter_only_no_jvmci()) {
+ if (!CompilerConfig::is_c1_or_interpreter_only_no_aot_or_jvmci()) {
Label notVolatile;
__ tbz(r3, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
__ membar(MacroAssembler::AnyAny);
@@ -3078,7 +3078,7 @@ void TemplateTable::fast_xaccess(TosState state)
// membar it's possible for a simple Dekker test to fail if loads
// use LDR;DMB but stores use STLR. This can happen if C2 compiles
// the stores in one method and we interpret the loads in another.
- if (!CompilerConfig::is_c1_or_interpreter_only_no_jvmci()) {
+ if (!CompilerConfig::is_c1_or_interpreter_only_no_aot_or_jvmci()) {
Label notVolatile;
__ ldrw(r3, Address(r2, in_bytes(ConstantPoolCache::base_offset() +
ConstantPoolCacheEntry::flags_offset())));
diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.hpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.hpp
index 77d135326..85ae89aed 100644
--- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.hpp
+++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -53,6 +53,7 @@
enum {
_call_stub_size = 16,
+ _call_aot_stub_size = 0,
_exception_handler_size = PRODUCT_ONLY(68) NOT_PRODUCT(68+60),
_deopt_handler_size = 16
};
diff --git a/src/hotspot/cpu/arm/compiledIC_arm.cpp b/src/hotspot/cpu/arm/compiledIC_arm.cpp
index f0272db02..e2860c940 100644
--- a/src/hotspot/cpu/arm/compiledIC_arm.cpp
+++ b/src/hotspot/cpu/arm/compiledIC_arm.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -102,7 +102,7 @@ int CompiledStaticCall::to_interp_stub_size() {
}
void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
- address stub = find_stub();
+ address stub = find_stub(/*is_aot*/ false);
guarantee(stub != NULL, "stub not found");
if (TraceICs) {
@@ -149,7 +149,7 @@ void CompiledDirectStaticCall::verify() {
_call->verify_alignment();
// Verify stub.
- address stub = find_stub();
+ address stub = find_stub(/*is_aot*/ false);
assert(stub != NULL, "no stub found for static call");
// Creation also verifies the object.
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp
index 861430b79..6a0e090d1 100644
--- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp
+++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2015 SAP SE. All rights reserved.
+ * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -62,6 +62,7 @@
enum {
_static_call_stub_size = 4 * BytesPerInstWord + MacroAssembler::b64_patchable_size, // or smaller
_call_stub_size = _static_call_stub_size + MacroAssembler::trampoline_stub_size, // or smaller
+ _call_aot_stub_size = 0,
_exception_handler_size = MacroAssembler::b64_patchable_size, // or smaller
_deopt_handler_size = MacroAssembler::bl64_patchable_size
};
@@ -69,7 +70,11 @@ enum {
// '_static_call_stub_size' is only used on ppc (see LIR_Assembler::emit_static_call_stub()
// in c1_LIRAssembler_ppc.cpp. The other, shared getters are defined in c1_LIRAssembler.hpp
static int static_call_stub_size() {
- return _static_call_stub_size;
+ if (UseAOT) {
+ return _static_call_stub_size + _call_aot_stub_size;
+ } else {
+ return _static_call_stub_size;
+ }
}
#endif // CPU_PPC_C1_LIRASSEMBLER_PPC_HPP
diff --git a/src/hotspot/cpu/ppc/compiledIC_ppc.cpp b/src/hotspot/cpu/ppc/compiledIC_ppc.cpp
index a112e472e..457ff485d 100644
--- a/src/hotspot/cpu/ppc/compiledIC_ppc.cpp
+++ b/src/hotspot/cpu/ppc/compiledIC_ppc.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2015 SAP SE. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -164,7 +164,7 @@ int CompiledStaticCall::reloc_to_interp_stub() {
}
void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
- address stub = find_stub();
+ address stub = find_stub(/*is_aot*/ false);
guarantee(stub != NULL, "stub not found");
if (TraceICs) {
@@ -210,7 +210,7 @@ void CompiledDirectStaticCall::verify() {
_call->verify_alignment();
// Verify stub.
- address stub = find_stub();
+ address stub = find_stub(/*is_aot*/ false);
assert(stub != NULL, "no stub found for static call");
// Creation also verifies the object.
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + IC_pos_in_java_to_interp_stub);
diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.hpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.hpp
index 7ca94d2d9..bba78a4d2 100644
--- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.hpp
+++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.hpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2023 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -47,6 +47,7 @@
enum {
_call_stub_size = 512, // See Compile::MAX_stubs_size and CompiledStaticCall::emit_to_interp_stub.
+ _call_aot_stub_size = 0,
_exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(128),
_deopt_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(64)
};
diff --git a/src/hotspot/cpu/s390/compiledIC_s390.cpp b/src/hotspot/cpu/s390/compiledIC_s390.cpp
index 6660a34ae..1cd1582bb 100644
--- a/src/hotspot/cpu/s390/compiledIC_s390.cpp
+++ b/src/hotspot/cpu/s390/compiledIC_s390.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016, 2019 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2023 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -92,7 +92,7 @@ int CompiledStaticCall::reloc_to_interp_stub() {
}
void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
- address stub = find_stub();
+ address stub = find_stub(/*is_aot*/ false);
guarantee(stub != NULL, "stub not found");
if (TraceICs) {
@@ -137,7 +137,7 @@ void CompiledDirectStaticCall::verify() {
_call->verify_alignment();
// Verify stub.
- address stub = find_stub();
+ address stub = find_stub(/*is_aot*/ false);
assert(stub != NULL, "no stub found for static call");
// Creation also verifies the object.
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + NativeCall::get_IC_pos_in_java_to_interp_stub());
diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp
index 592efea82..c079c65a9 100644
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -2894,13 +2894,23 @@ void LIR_Assembler::emit_static_call_stub() {
// make sure that the displacement word of the call ends up word aligned
__ align(BytesPerWord, __ offset() + NativeMovConstReg::instruction_size + NativeCall::displacement_offset);
- __ relocate(static_stub_Relocation::spec(call_pc));
+ __ relocate(static_stub_Relocation::spec(call_pc, false /* is_aot */));
__ mov_metadata(rbx, (Metadata*)NULL);
// must be set to -1 at code generation time
assert(((__ offset() + 1) % BytesPerWord) == 0, "must be aligned");
// On 64bit this will die since it will take a movq & jmp, must be only a jmp
__ jump(RuntimeAddress(__ pc()));
+ if (UseAOT) {
+ // Trampoline to aot code
+ __ relocate(static_stub_Relocation::spec(call_pc, true /* is_aot */));
+#ifdef _LP64
+ __ mov64(rax, CONST64(0)); // address is zapped till fixup time.
+#else
+ __ movl(rax, 0xdeadffff); // address is zapped till fixup time.
+#endif
+ __ jmp(rax);
+ }
assert(__ offset() - start <= call_stub_size(), "stub too big");
__ end_a_stub();
}
diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp
index 10270f4fb..40322f669 100644
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp
+++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -48,6 +48,7 @@
enum {
_call_stub_size = NOT_LP64(15) LP64_ONLY(28),
+ _call_aot_stub_size = NOT_LP64(7) LP64_ONLY(12),
_exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175),
_deopt_handler_size = NOT_LP64(10) LP64_ONLY(17)
};
diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp
index b022f1199..70cd943a5 100644
--- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -336,7 +336,7 @@ void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_by
mov(rbp, rsp);
}
#if !defined(_LP64) && defined(COMPILER2)
- if (UseSSE < 2 && !CompilerConfig::is_c1_only_no_jvmci()) {
+ if (UseSSE < 2 && !CompilerConfig::is_c1_only_no_aot_or_jvmci()) {
// c2 leaves fpu stack dirty. Clean it on entry
empty_FPU_stack();
}
diff --git a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp
index 42c46496d..031ba9c1c 100644
--- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp
+++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -723,7 +723,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
}
#if !defined(_LP64) && defined(COMPILER2)
- if (UseSSE < 2 && !CompilerConfig::is_c1_only_no_jvmci()) {
+ if (UseSSE < 2 && !CompilerConfig::is_c1_only_no_aot_or_jvmci()) {
// C2 can leave the fpu stack dirty
__ empty_FPU_stack();
}
diff --git a/src/hotspot/cpu/x86/compiledIC_aot_x86_64.cpp b/src/hotspot/cpu/x86/compiledIC_aot_x86_64.cpp
new file mode 100644
index 000000000..9e3e87de7
--- /dev/null
+++ b/src/hotspot/cpu/x86/compiledIC_aot_x86_64.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+
+#include "aot/compiledIC_aot.hpp"
+#include "code/codeCache.hpp"
+#include "memory/resourceArea.hpp"
+
+void CompiledDirectStaticCall::set_to_far(const methodHandle& callee, address entry) {
+ address stub = find_stub(true /* is_far */);
+ guarantee(stub != NULL, "stub not found");
+
+ if (TraceICs) {
+ ResourceMark rm;
+ tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_far %s",
+ p2i(instruction_address()),
+ callee->name_and_sig_as_C_string());
+ }
+
+ // Creation also verifies the object.
+ // mov rax,imm_aot_addr
+ // jmp rax
+ NativeMovConstReg* destination_holder = nativeMovConstReg_at(stub);
+
+#ifdef ASSERT
+ // read the value once
+ intptr_t data = destination_holder->data();
+ assert(data == 0 || data == (intptr_t)entry,
+ "MT-unsafe modification of inline cache");
+#endif
+
+ // Update stub.
+ destination_holder->set_data((intptr_t)entry);
+
+ // Update jump to call.
+ set_destination_mt_safe(stub);
+}
+
+void CompiledPltStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
+ address stub = find_stub();
+ guarantee(stub != NULL, "stub not found");
+ if (TraceICs) {
+ ResourceMark rm;
+ tty->print_cr("CompiledPltStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
+ p2i(instruction_address()),
+ callee->name_and_sig_as_C_string());
+ }
+
+ // Creation also verifies the object.
+ NativeLoadGot* method_loader = nativeLoadGot_at(stub);
+ NativeGotJump* jump = nativeGotJump_at(method_loader->next_instruction_address());
+
+ intptr_t data = method_loader->data();
+ address destination = jump->destination();
+ assert(data == 0 || data == (intptr_t)callee(),
+ "a) MT-unsafe modification of inline cache");
+ assert(destination == (address)-1 || destination == entry,
+ "b) MT-unsafe modification of inline cache");
+
+ // Update stub.
+ method_loader->set_data((intptr_t)callee());
+ jump->set_jump_destination(entry);
+
+ // Update jump to call.
+ set_destination_mt_safe(stub);
+}
+
+#ifdef NEVER_CALLED
+void CompiledPltStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
+ // Reset stub.
+ address stub = static_stub->addr();
+ assert(stub != NULL, "stub not found");
+ assert(CompiledICLocker::is_safe(stub), "mt unsafe call");
+ // Creation also verifies the object.
+ NativeLoadGot* method_loader = nativeLoadGot_at(stub);
+ NativeGotJump* jump = nativeGotJump_at(method_loader->next_instruction_address());
+ method_loader->set_data(0);
+ jump->set_jump_destination((address)-1);
+}
+#endif
+
+#ifndef PRODUCT
+void CompiledPltStaticCall::verify() {
+ // Verify call.
+ _call->verify();
+
+#ifdef ASSERT
+ CodeBlob *cb = CodeCache::find_blob_unsafe((address) _call);
+ assert(cb && cb->is_aot(), "CompiledPltStaticCall can only be used on AOTCompiledMethod");
+#endif
+
+ // Verify stub.
+ address stub = find_stub();
+ assert(stub != NULL, "no stub found for static call");
+ // Creation also verifies the object.
+ NativeLoadGot* method_loader = nativeLoadGot_at(stub);
+ NativeGotJump* jump = nativeGotJump_at(method_loader->next_instruction_address());
+ // Verify state.
+ assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check");
+}
+#endif // !PRODUCT
diff --git a/src/hotspot/cpu/x86/compiledIC_x86.cpp b/src/hotspot/cpu/x86/compiledIC_x86.cpp
index e898e523c..504973517 100644
--- a/src/hotspot/cpu/x86/compiledIC_x86.cpp
+++ b/src/hotspot/cpu/x86/compiledIC_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -54,7 +54,7 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark)
return NULL; // CodeBuffer::expand failed.
}
// Static stub relocation stores the instruction address of the call.
- __ relocate(static_stub_Relocation::spec(mark), Assembler::imm_operand);
+ __ relocate(static_stub_Relocation::spec(mark, false), Assembler::imm_operand);
// Static stub relocation also tags the Method* in the code-stream.
__ mov_metadata(rbx, (Metadata*) NULL); // Method is zapped till fixup time.
// This is recognized as unresolved by relocs/nativeinst/ic code.
@@ -83,8 +83,68 @@ int CompiledStaticCall::reloc_to_interp_stub() {
return 4; // 3 in emit_to_interp_stub + 1 in emit_call
}
+#if INCLUDE_AOT
+#define __ _masm.
+void CompiledStaticCall::emit_to_aot_stub(CodeBuffer &cbuf, address mark) {
+ if (!UseAOT) {
+ return;
+ }
+ // Stub is fixed up when the corresponding call is converted from
+ // calling compiled code to calling aot code.
+ // movq rax, imm64_aot_code_address
+ // jmp rax
+
+ if (mark == NULL) {
+ mark = cbuf.insts_mark(); // Get mark within main instrs section.
+ }
+
+ // Note that the code buffer's insts_mark is always relative to insts.
+ // That's why we must use the macroassembler to generate a stub.
+ MacroAssembler _masm(&cbuf);
+
+ address base =
+ __ start_a_stub(to_aot_stub_size());
+ guarantee(base != NULL, "out of space");
+
+ // Static stub relocation stores the instruction address of the call.
+ __ relocate(static_stub_Relocation::spec(mark, true /* is_aot */), Assembler::imm_operand);
+ // Load destination AOT code address.
+#ifdef _LP64
+ __ mov64(rax, CONST64(0)); // address is zapped till fixup time.
+#else
+ __ movl(rax, 0); // address is zapped till fixup time.
+#endif
+ // This is recognized as unresolved by relocs/nativeinst/ic code.
+ __ jmp(rax);
+
+ assert(__ pc() - base <= to_aot_stub_size(), "wrong stub size");
+
+ // Update current stubs pointer and restore insts_end.
+ __ end_a_stub();
+}
+#undef __
+
+int CompiledStaticCall::to_aot_stub_size() {
+ if (UseAOT) {
+ return NOT_LP64(7) // movl; jmp
+ LP64_ONLY(12); // movq (1+1+8); jmp (2)
+ } else {
+ return 0;
+ }
+}
+
+// Relocation entries for call stub, compiled java to aot.
+int CompiledStaticCall::reloc_to_aot_stub() {
+ if (UseAOT) {
+ return 2; // 1 in emit_to_aot_stub + 1 in emit_call
+ } else {
+ return 0;
+ }
+}
+#endif // INCLUDE_AOT
+
void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
- address stub = find_stub();
+ address stub = find_stub(false /* is_aot */);
guarantee(stub != NULL, "stub not found");
if (TraceICs) {
@@ -115,8 +175,10 @@ void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_
// Creation also verifies the object.
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
method_holder->set_data(0);
- NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
- jump->set_jump_destination((address)-1);
+ if (!static_stub->is_aot()) {
+ NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
+ jump->set_jump_destination((address)-1);
+ }
}
@@ -131,11 +193,11 @@ void CompiledDirectStaticCall::verify() {
#ifdef ASSERT
CodeBlob *cb = CodeCache::find_blob_unsafe((address) _call);
- assert(cb != NULL, "sanity");
+ assert(cb && !cb->is_aot(), "CompiledDirectStaticCall cannot be used on AOTCompiledMethod");
#endif
// Verify stub.
- address stub = find_stub();
+ address stub = find_stub(false /* is_aot */);
assert(stub != NULL, "no stub found for static call");
// Creation also verifies the object.
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
diff --git a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp
index 60e8b0d22..d27f68c7a 100644
--- a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp
+++ b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -70,7 +70,7 @@ const bool CCallingConventionRequiresIntsAsLongs = false;
#endif
#if INCLUDE_JVMCI
-#define COMPRESSED_CLASS_POINTERS_DEPENDS_ON_COMPRESSED_OOPS EnableJVMCI
+#define COMPRESSED_CLASS_POINTERS_DEPENDS_ON_COMPRESSED_OOPS (EnableJVMCI || UseAOT)
#else
#define COMPRESSED_CLASS_POINTERS_DEPENDS_ON_COMPRESSED_OOPS false
#endif
diff --git a/src/hotspot/cpu/x86/nativeInst_x86.hpp b/src/hotspot/cpu/x86/nativeInst_x86.hpp
index a86128e7e..a7fc40732 100644
--- a/src/hotspot/cpu/x86/nativeInst_x86.hpp
+++ b/src/hotspot/cpu/x86/nativeInst_x86.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -198,6 +198,13 @@ class NativeCall: public NativeInstruction {
nativeCall_at(instr)->destination() == target;
}
+#if INCLUDE_AOT
+ static bool is_far_call(address instr, address target) {
+ intptr_t disp = target - (instr + sizeof(int32_t));
+ return !Assembler::is_simm32(disp);
+ }
+#endif
+
// MT-safe patching of a call instruction.
static void insert(address code_pos, address entry);
diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
index f912b7650..5dd8f952a 100644
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -847,7 +847,7 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
__ movptr(r11, Address(rbx, in_bytes(Method::from_compiled_offset())));
#if INCLUDE_JVMCI
- if (EnableJVMCI) {
+ if (EnableJVMCI || UseAOT) {
// check if this call should be routed towards a specific entry point
__ cmpptr(Address(r15_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), 0);
Label no_alternative_target;
@@ -2456,7 +2456,7 @@ void SharedRuntime::generate_deopt_blob() {
pad += 1024;
}
#if INCLUDE_JVMCI
- if (EnableJVMCI) {
+ if (EnableJVMCI || UseAOT) {
pad += 512; // Increase the buffer size when compiling for JVMCI
}
#endif
@@ -2530,7 +2530,7 @@ void SharedRuntime::generate_deopt_blob() {
int implicit_exception_uncommon_trap_offset = 0;
int uncommon_trap_offset = 0;
- if (EnableJVMCI) {
+ if (EnableJVMCI || UseAOT) {
implicit_exception_uncommon_trap_offset = __ pc() - start;
__ pushptr(Address(r15_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset())));
@@ -2645,7 +2645,7 @@ void SharedRuntime::generate_deopt_blob() {
__ reset_last_Java_frame(false);
#if INCLUDE_JVMCI
- if (EnableJVMCI) {
+ if (EnableJVMCI || UseAOT) {
__ bind(after_fetch_unroll_info_call);
}
#endif
@@ -2808,7 +2808,7 @@ void SharedRuntime::generate_deopt_blob() {
_deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words);
_deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
#if INCLUDE_JVMCI
- if (EnableJVMCI) {
+ if (EnableJVMCI || UseAOT) {
_deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset);
_deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset);
}
diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp
index dcbb37333..59d2c1938 100644
--- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp
+++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -261,7 +261,7 @@ address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, i
#if INCLUDE_JVMCI
// Check if we need to take lock at entry of synchronized method. This can
// only occur on method entry so emit it only for vtos with step 0.
- if (EnableJVMCI && state == vtos && step == 0) {
+ if ((EnableJVMCI || UseAOT) && state == vtos && step == 0) {
Label L;
__ cmpb(Address(thread, JavaThread::pending_monitorenter_offset()), 0);
__ jcc(Assembler::zero, L);
diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad
index 654b92db5..a6b419111 100644
--- a/src/hotspot/cpu/x86/x86_64.ad
+++ b/src/hotspot/cpu/x86/x86_64.ad
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// This code is free software; you can redistribute it and/or modify it
@@ -2158,6 +2158,9 @@ encode %{
ciEnv::current()->record_failure("CodeCache is full");
return;
}
+#if INCLUDE_AOT
+ CompiledStaticCall::emit_to_aot_stub(cbuf, mark);
+#endif
}
%}
diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp
index 535b795fa..c9b9e2676 100644
--- a/src/hotspot/os/windows/os_windows.cpp
+++ b/src/hotspot/os/windows/os_windows.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -131,6 +131,9 @@ static FILETIME process_kernel_time;
#if defined(USE_VECTORED_EXCEPTION_HANDLING)
PVOID topLevelVectoredExceptionHandler = NULL;
LPTOP_LEVEL_EXCEPTION_FILTER previousUnhandledExceptionFilter = NULL;
+#elif INCLUDE_AOT
+PVOID topLevelVectoredExceptionHandler = NULL;
+LONG WINAPI topLevelVectoredExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo);
#endif
// save DLL module handle, used by GetModuleFileName
@@ -151,7 +154,7 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) {
if (ForceTimeHighResolution) {
timeEndPeriod(1L);
}
-#if defined(USE_VECTORED_EXCEPTION_HANDLING)
+#if defined(USE_VECTORED_EXCEPTION_HANDLING) || INCLUDE_AOT
if (topLevelVectoredExceptionHandler != NULL) {
RemoveVectoredExceptionHandler(topLevelVectoredExceptionHandler);
topLevelVectoredExceptionHandler = NULL;
@@ -2833,7 +2836,7 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
return EXCEPTION_CONTINUE_SEARCH;
}
-#if defined(USE_VECTORED_EXCEPTION_HANDLING)
+#if defined(USE_VECTORED_EXCEPTION_HANDLING) || INCLUDE_AOT
LONG WINAPI topLevelVectoredExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord;
#if defined(_M_ARM64)
@@ -2849,7 +2852,9 @@ LONG WINAPI topLevelVectoredExceptionFilter(struct _EXCEPTION_POINTERS* exceptio
return topLevelExceptionFilter(exceptionInfo);
}
- // If the exception occurred in the codeCache, pass control
+ // Handle the case where we get an implicit exception in AOT generated
+ // code. AOT DLL's loaded are not registered for structured exceptions.
+ // If the exception occurred in the codeCache or AOT code, pass control
// to our normal exception handler.
CodeBlob* cb = CodeCache::find_blob(pc);
if (cb != NULL) {
@@ -4354,6 +4359,14 @@ jint os::init_2(void) {
#if defined(USE_VECTORED_EXCEPTION_HANDLING)
topLevelVectoredExceptionHandler = AddVectoredExceptionHandler(1, topLevelVectoredExceptionFilter);
previousUnhandledExceptionFilter = SetUnhandledExceptionFilter(topLevelUnhandledExceptionFilter);
+#elif INCLUDE_AOT
+ // If AOT is enabled we need to install a vectored exception handler
+ // in order to forward implicit exceptions from code in AOT
+ // generated DLLs. This is necessary since these DLLs are not
+ // registered for structured exceptions like codecache methods are.
+ if (AOTLibrary != NULL && (UseAOT || FLAG_IS_DEFAULT(UseAOT))) {
+ topLevelVectoredExceptionHandler = AddVectoredExceptionHandler( 1, topLevelVectoredExceptionFilter);
+ }
#endif
// for debugging float code generation bugs
diff --git a/src/hotspot/share/aot/aotCodeHeap.cpp b/src/hotspot/share/aot/aotCodeHeap.cpp
new file mode 100644
index 000000000..153ef67bb
--- /dev/null
+++ b/src/hotspot/share/aot/aotCodeHeap.cpp
@@ -0,0 +1,1116 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+#include "jvm_io.h"
+#include "aot/aotCodeHeap.hpp"
+#include "aot/aotLoader.hpp"
+#include "ci/ciUtilities.inline.hpp"
+#include "classfile/javaAssertions.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "classfile/vmClasses.hpp"
+#include "classfile/vmSymbols.hpp"
+#include "gc/shared/cardTable.hpp"
+#include "gc/shared/cardTableBarrierSet.hpp"
+#include "gc/shared/gcConfig.hpp"
+#include "gc/shared/tlab_globals.hpp"
+#include "gc/g1/heapRegion.hpp"
+#include "interpreter/abstractInterpreter.hpp"
+#include "jvmci/compilerRuntime.hpp"
+#include "jvmci/jvmciRuntime.hpp"
+#include "logging/log.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/universe.hpp"
+#include "oops/compressedOops.hpp"
+#include "oops/klass.inline.hpp"
+#include "oops/method.inline.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/deoptimization.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/os.hpp"
+#include "runtime/java.hpp"
+#include "runtime/safepointVerifiers.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/vmOperations.hpp"
+#include "utilities/powerOfTwo.hpp"
+#include "utilities/sizes.hpp"
+
+bool AOTLib::_narrow_oop_shift_initialized = false;
+int AOTLib::_narrow_oop_shift = 0;
+int AOTLib::_narrow_klass_shift = 0;
+
+address AOTLib::load_symbol(const char *name) {
+ address symbol = (address) os::dll_lookup(_dl_handle, name);
+ if (symbol == NULL) {
+ tty->print_cr("Shared file %s error: missing %s", _name, name);
+ vm_exit(1);
+ }
+ return symbol;
+}
+
+Klass* AOTCodeHeap::get_klass_from_got(const char* klass_name, int klass_len, const Method* method) {
+ AOTKlassData* klass_data = (AOTKlassData*)_lib->load_symbol(klass_name);
+ Klass* k = (Klass*)_klasses_got[klass_data->_got_index];
+ if (k == NULL) {
+ Thread* thread = Thread::current();
+ k = lookup_klass(klass_name, klass_len, method, thread);
+ // Note, exceptions are cleared.
+ if (k == NULL) {
+ fatal("Shared file %s error: klass %s should be resolved already", _lib->name(), klass_name);
+ vm_exit(1);
+ }
+ // Patch now to avoid extra runtime lookup
+ _klasses_got[klass_data->_got_index] = k;
+ if (k->is_instance_klass()) {
+ InstanceKlass* ik = InstanceKlass::cast(k);
+ if (ik->is_initialized()) {
+ _klasses_got[klass_data->_got_index - 1] = ik;
+ }
+ }
+ }
+ return k;
+}
+
+Klass* AOTCodeHeap::lookup_klass(const char* name, int len, const Method* method, Thread* thread) {
+ ResourceMark rm(thread);
+ assert(method != NULL, "incorrect call parameter");
+ methodHandle caller(thread, (Method*)method);
+
+ // Use class loader of aot method.
+ Handle loader(thread, caller->method_holder()->class_loader());
+ Handle protection_domain(thread, caller->method_holder()->protection_domain());
+
+ // Ignore wrapping L and ;
+ if (name[0] == JVM_SIGNATURE_CLASS) {
+ assert(len > 2, "small name %s", name);
+ name++;
+ len -= 2;
+ }
+ TempNewSymbol sym = SymbolTable::probe(name, len);
+ if (sym == NULL) {
+ log_debug(aot, class, resolve)("Probe failed for AOT class %s", name);
+ return NULL;
+ }
+ Klass* k = SystemDictionary::find_instance_or_array_klass(sym, loader, protection_domain);
+
+ if (k != NULL) {
+ log_info(aot, class, resolve)("%s %s (lookup)", caller->method_holder()->external_name(), k->external_name());
+ }
+ return k;
+}
+
+void AOTLib::handle_config_error(const char* format, ...) {
+ if (PrintAOT) {
+ va_list ap;
+ va_start(ap, format);
+ tty->vprint_cr(format, ap);
+ va_end(ap);
+ }
+ if (UseAOTStrictLoading) {
+ vm_exit(1);
+ }
+ _valid = false;
+}
+
+void AOTLib::verify_flag(bool aot_flag, bool flag, const char* name) {
+ if (_valid && aot_flag != flag) {
+ handle_config_error("Shared file %s error: %s has different value '%s' from current '%s'", _name, name , (aot_flag ? "true" : "false"), (flag ? "true" : "false"));
+ }
+}
+
+void AOTLib::verify_flag(int aot_flag, int flag, const char* name) {
+ if (_valid && aot_flag != flag) {
+ handle_config_error("Shared file %s error: %s has different value '%d' from current '%d'", _name, name , aot_flag, flag);
+ }
+}
+
+void AOTLib::verify_config() {
+ GrowableArray<AOTLib*>* libraries = AOTLoader::libraries();
+ for (GrowableArrayIterator<AOTLib*> lib = libraries->begin(); lib != libraries->end(); ++lib) {
+ if ((*lib)->_config == _config) {
+ handle_config_error("AOT library %s already loaded.", (*lib)->_name);
+ return;
+ }
+ }
+
+ if (_header->_version != AOTHeader::AOT_SHARED_VERSION) {
+ handle_config_error("Invalid version of the shared file %s. Expected %d but was %d", _name, _header->_version, AOTHeader::AOT_SHARED_VERSION);
+ return;
+ }
+
+ const char* aot_jvm_version = (const char*)_header + _header->_jvm_version_offset + 2;
+ if (strcmp(aot_jvm_version, VM_Version::jre_release_version()) != 0) {
+ handle_config_error("JVM version '%s' recorded in the shared file %s does not match current version '%s'", aot_jvm_version, _name, VM_Version::jre_release_version());
+ return;
+ }
+
+ // Debug VM has different layout of runtime and metadata structures
+#ifdef ASSERT
+ verify_flag(_config->_debug_VM, true, "Debug VM version");
+#else
+ verify_flag(!(_config->_debug_VM), true, "Product VM version");
+#endif
+ // Check configuration size
+ verify_flag(_config->_config_size, AOTConfiguration::CONFIG_SIZE, "AOT configuration size");
+
+ // Check GC
+ CollectedHeap::Name gc = (CollectedHeap::Name)_config->_gc;
+ if (_valid && !GCConfig::is_gc_selected(gc)) {
+ handle_config_error("Shared file %s error: used '%s' is different from current '%s'", _name, GCConfig::hs_err_name(gc), GCConfig::hs_err_name());
+ }
+
+ // Check flags
+ verify_flag(_config->_useCompressedOops, UseCompressedOops, "UseCompressedOops");
+ verify_flag(_config->_useCompressedClassPointers, UseCompressedClassPointers, "UseCompressedClassPointers");
+ verify_flag(_config->_useTLAB, UseTLAB, "UseTLAB");
+ verify_flag(_config->_useBiasedLocking, UseBiasedLocking, "UseBiasedLocking");
+ verify_flag(_config->_objectAlignment, ObjectAlignmentInBytes, "ObjectAlignmentInBytes");
+ verify_flag(_config->_contendedPaddingWidth, ContendedPaddingWidth, "ContendedPaddingWidth");
+ verify_flag(_config->_enableContended, EnableContended, "EnableContended");
+ verify_flag(_config->_restrictContended, RestrictContended, "RestrictContended");
+
+ // Shifts are static values which initialized by 0 until java heap initialization.
+ // AOT libs are loaded before heap initialized so shift values are not set.
+ // It is okay since ObjectAlignmentInBytes flag which defines shifts value is set before AOT libs are loaded.
+ // Set shifts value based on first AOT library config.
+ if (UseCompressedOops && _valid) {
+ if (!_narrow_oop_shift_initialized) {
+ _narrow_oop_shift = _config->_narrowOopShift;
+ if (UseCompressedClassPointers) { // It is set only if UseCompressedOops is set
+ _narrow_klass_shift = _config->_narrowKlassShift;
+ }
+ _narrow_oop_shift_initialized = true;
+ } else {
+ verify_flag(_config->_narrowOopShift, _narrow_oop_shift, "aot_config->_narrowOopShift");
+ if (UseCompressedClassPointers) { // It is set only if UseCompressedOops is set
+ verify_flag(_config->_narrowKlassShift, _narrow_klass_shift, "aot_config->_narrowKlassShift");
+ }
+ }
+ }
+}
+
+AOTLib::~AOTLib() {
+ os::free((void*) _name);
+}
+
+AOTCodeHeap::~AOTCodeHeap() {
+ FREE_C_HEAP_ARRAY(AOTClass, _classes);
+ FREE_C_HEAP_ARRAY(CodeToAMethod, _code_to_aot);
+}
+
+AOTLib::AOTLib(void* handle, const char* name, int dso_id) : _valid(true), _dl_handle(handle), _dso_id(dso_id) {
+ _name = (const char*) os::strdup(name);
+
+ // Verify that VM runs with the same parameters as AOT tool.
+ _config = (AOTConfiguration*) load_symbol("A.config");
+ _header = (AOTHeader*) load_symbol("A.header");
+
+ verify_config();
+
+ if (!_valid && PrintAOT) {
+ tty->print("%7d ", (int) tty->time_stamp().milliseconds());
+ tty->print_cr("%4d skipped %s aot library", _dso_id, _name);
+ }
+}
+
+AOTCodeHeap::AOTCodeHeap(AOTLib* lib) :
+ CodeHeap("CodeHeap 'AOT'", CodeBlobType::AOT), _lib(lib), _classes(NULL), _code_to_aot(NULL) {
+ assert(_lib->is_valid(), "invalid library");
+
+ _lib_symbols_initialized = false;
+ _aot_id = 0;
+
+ _class_count = _lib->header()->_class_count;
+ _method_count = _lib->header()->_method_count;
+
+ // Collect metaspace info: names -> address in .got section
+ _metaspace_names = (const char*) _lib->load_symbol("A.meta.names");
+ _method_metadata = (address) _lib->load_symbol("A.meth.metadata");
+ _methods_offsets = (address) _lib->load_symbol("A.meth.offsets");
+ _klasses_offsets = (address) _lib->load_symbol("A.kls.offsets");
+ _dependencies = (address) _lib->load_symbol("A.kls.dependencies");
+ _code_space = (address) _lib->load_symbol("A.text");
+
+ // First cell is number of elements.
+ _klasses_got = (Metadata**) _lib->load_symbol("A.kls.got");
+ _klasses_got_size = _lib->header()->_klasses_got_size;
+
+ _metadata_got = (Metadata**) _lib->load_symbol("A.meta.got");
+ _metadata_got_size = _lib->header()->_metadata_got_size;
+
+ _oop_got = (oop*) _lib->load_symbol("A.oop.got");
+ _oop_got_size = _lib->header()->_oop_got_size;
+
+ // Collect stubs info
+ _stubs_offsets = (int*) _lib->load_symbol("A.stubs.offsets");
+
+ // code segments table
+ _code_segments = (address) _lib->load_symbol("A.code.segments");
+
+ // method state
+ _method_state = (jlong*) _lib->load_symbol("A.meth.state");
+
+ // Create a table for mapping classes
+ _classes = NEW_C_HEAP_ARRAY(AOTClass, _class_count, mtCode);
+ memset(_classes, 0, _class_count * sizeof(AOTClass));
+
+ // Create table for searching AOTCompiledMethod based on pc.
+ _code_to_aot = NEW_C_HEAP_ARRAY(CodeToAMethod, _method_count, mtCode);
+ memset(_code_to_aot, 0, _method_count * sizeof(CodeToAMethod));
+
+ _memory.set_low_boundary((char *)_code_space);
+ _memory.set_high_boundary((char *)_code_space);
+ _memory.set_low((char *)_code_space);
+ _memory.set_high((char *)_code_space);
+
+ _segmap.set_low_boundary((char *)_code_segments);
+ _segmap.set_low((char *)_code_segments);
+
+ _log2_segment_size = exact_log2(_lib->config()->_codeSegmentSize);
+
+ // Register aot stubs
+ register_stubs();
+
+ if (PrintAOT || (PrintCompilation && PrintAOT)) {
+ tty->print("%7d ", (int) tty->time_stamp().milliseconds());
+ tty->print_cr("%4d loaded %s aot library", _lib->id(), _lib->name());
+ }
+}
+
+void AOTCodeHeap::publish_aot(const methodHandle& mh, AOTMethodData* method_data, int code_id) {
+ // The method may be explicitly excluded by the user.
+ // Or Interpreter uses an intrinsic for this method.
+ // Or method has breakpoints.
+ if (CompilerOracle::should_exclude(mh) ||
+ !AbstractInterpreter::can_be_compiled(mh) ||
+ (mh->number_of_breakpoints() > 0)) {
+ return;
+ }
+ // Make sure no break points were set in the method in case of a safepoint
+ // in the following code until aot code is registered.
+ NoSafepointVerifier nsv;
+
+ address code = method_data->_code;
+ const char* name = method_data->_name;
+ aot_metadata* meta = method_data->_meta;
+
+ if (meta->scopes_pcs_begin() == meta->scopes_pcs_end()) {
+ // Switch off NoSafepointVerifier because log_info() may cause safepoint
+ // and it is fine because aot code will not be registered here.
+ PauseNoSafepointVerifier pnsv(&nsv);
+
+ // When the AOT compiler compiles something big we fail to generate metadata
+ // in CodeInstaller::gather_metadata. In that case the scopes_pcs_begin == scopes_pcs_end.
+ // In all successful cases we always have 2 entries of scope pcs.
+ log_info(aot, class, resolve)("Failed to load %s (no metadata available)", mh->name_and_sig_as_C_string());
+ _code_to_aot[code_id]._state = invalid;
+ return;
+ }
+
+ jlong* state_adr = &_method_state[code_id];
+ address metadata_table = method_data->_metadata_table;
+ int metadata_size = method_data->_metadata_size;
+ assert(code_id < _method_count, "sanity");
+ _aot_id++;
+
+#ifdef ASSERT
+ if (_aot_id > CIStop || _aot_id < CIStart) {
+ // Skip compilation
+ return;
+ }
+#endif
+ // Check one more time.
+ if (_code_to_aot[code_id]._state == invalid) {
+ return;
+ }
+ AOTCompiledMethod *aot = new AOTCompiledMethod(code, mh(), meta, metadata_table, metadata_size, state_adr, this, name, code_id, _aot_id);
+ assert(_code_to_aot[code_id]._aot == NULL, "should be not initialized");
+ _code_to_aot[code_id]._aot = aot; // Should set this first
+ if (Atomic::cmpxchg(&_code_to_aot[code_id]._state, not_set, in_use) != not_set) {
+ _code_to_aot[code_id]._aot = NULL; // Clean
+ } else { // success
+ // Publish method
+#if COMPILER1_OR_COMPILER2
+ mh->set_aot_code(aot);
+#endif
+ {
+ MutexLocker pl(CompiledMethod_lock, Mutex::_no_safepoint_check_flag);
+ Method::set_code(mh, aot);
+ }
+ if (PrintAOT || (PrintCompilation && PrintAOT)) {
+ PauseNoSafepointVerifier pnsv(&nsv); // aot code is registered already
+ aot->print_on(tty, NULL);
+ }
+ // Publish oop only after we are visible to CompiledMethodIterator
+ aot->set_oop(mh()->method_holder()->klass_holder());
+ }
+}
+
+void AOTCodeHeap::link_klass(const Klass* klass) {
+ ResourceMark rm;
+ assert(klass != NULL, "Should be given a klass");
+ AOTKlassData* klass_data = (AOTKlassData*) os::dll_lookup(_lib->dl_handle(), klass->signature_name());
+ if (klass_data != NULL) {
+ // Set both GOT cells, resolved and initialized klass pointers.
+ // _got_index points to second cell - resolved klass pointer.
+ _klasses_got[klass_data->_got_index-1] = (Metadata*)klass; // Initialized
+ _klasses_got[klass_data->_got_index ] = (Metadata*)klass; // Resolved
+ if (PrintAOT) {
+ tty->print_cr("[Found %s in %s]", klass->internal_name(), _lib->name());
+ }
+ }
+}
+
+void AOTCodeHeap::link_known_klasses() {
+ for (int i = T_BOOLEAN; i <= T_CONFLICT; i++) {
+ BasicType t = (BasicType)i;
+ if (is_java_primitive(t)) {
+ const Klass* arr_klass = Universe::typeArrayKlassObj(t);
+ link_klass(arr_klass);
+ }
+ }
+ link_klass(vmClasses::Reference_klass());
+}
+
+void AOTCodeHeap::register_stubs() {
+ int stubs_count = _stubs_offsets[0]; // contains number
+ _stubs_offsets++;
+ AOTMethodOffsets* stub_offsets = (AOTMethodOffsets*)_stubs_offsets;
+ for (int i = 0; i < stubs_count; ++i) {
+ const char* stub_name = _metaspace_names + stub_offsets[i]._name_offset;
+ address entry = _code_space + stub_offsets[i]._code_offset;
+ aot_metadata* meta = (aot_metadata *) (_method_metadata + stub_offsets[i]._meta_offset);
+ address metadata_table = (address)_metadata_got + stub_offsets[i]._metadata_got_offset;
+ int metadata_size = stub_offsets[i]._metadata_got_size;
+ int code_id = stub_offsets[i]._code_id;
+ assert(code_id < _method_count, "sanity");
+ jlong* state_adr = &_method_state[code_id];
+ int len = Bytes::get_Java_u2((address)stub_name);
+ stub_name += 2;
+ char* full_name = NEW_C_HEAP_ARRAY(char, len+5, mtCode);
+ memcpy(full_name, "AOT ", 4);
+ memcpy(full_name+4, stub_name, len);
+ full_name[len+4] = 0;
+ guarantee(_code_to_aot[code_id]._state != invalid, "stub %s can't be invalidated", full_name);
+ AOTCompiledMethod* aot = new AOTCompiledMethod(entry, NULL, meta, metadata_table, metadata_size, state_adr, this, full_name, code_id, i);
+ assert(_code_to_aot[code_id]._aot == NULL, "should be not initialized");
+ _code_to_aot[code_id]._aot = aot;
+ if (Atomic::cmpxchg(&_code_to_aot[code_id]._state, not_set, in_use) != not_set) {
+ fatal("stab '%s' code state is %d", full_name, _code_to_aot[code_id]._state);
+ }
+ // Adjust code buffer boundaries only for stubs because they are last in the buffer.
+ adjust_boundaries(aot);
+ if (PrintAOT && Verbose) {
+ aot->print_on(tty, NULL);
+ }
+ }
+}
+
+#define SET_AOT_GLOBAL_SYMBOL_VALUE(AOTSYMNAME, AOTSYMTYPE, VMSYMVAL) \
+ { \
+ AOTSYMTYPE * adr = (AOTSYMTYPE *) os::dll_lookup(_lib->dl_handle(), AOTSYMNAME); \
+ /* Check for a lookup error */ \
+ guarantee(adr != NULL, "AOT Symbol not found %s", AOTSYMNAME); \
+ *adr = (AOTSYMTYPE) VMSYMVAL; \
+ }
+
+void AOTCodeHeap::link_graal_runtime_symbols() {
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_monitorenter", address, JVMCIRuntime::monitorenter);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_monitorexit", address, JVMCIRuntime::monitorexit);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_log_object", address, JVMCIRuntime::log_object);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_log_printf", address, JVMCIRuntime::log_printf);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_log_primitive", address, JVMCIRuntime::log_primitive);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_new_instance", address, JVMCIRuntime::new_instance);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_new_array", address, JVMCIRuntime::new_array);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_new_multi_array", address, JVMCIRuntime::new_multi_array);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_dynamic_new_instance", address, JVMCIRuntime::dynamic_new_instance);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_dynamic_new_array", address, JVMCIRuntime::dynamic_new_array);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_new_instance_or_null", address, JVMCIRuntime::new_instance_or_null);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_new_array_or_null", address, JVMCIRuntime::new_array_or_null);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_new_multi_array_or_null", address, JVMCIRuntime::new_multi_array_or_null);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_dynamic_new_instance_or_null", address, JVMCIRuntime::dynamic_new_instance_or_null);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_dynamic_new_array_or_null", address, JVMCIRuntime::dynamic_new_array_or_null);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_validate_object", address, JVMCIRuntime::validate_object);
+#if INCLUDE_G1GC
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_write_barrier_pre", address, JVMCIRuntime::write_barrier_pre);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_write_barrier_post", address, JVMCIRuntime::write_barrier_post);
+#endif
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_identity_hash_code", address, JVMCIRuntime::identity_hash_code);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_exception_handler_for_pc", address, JVMCIRuntime::exception_handler_for_pc);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_test_deoptimize_call_int", address, JVMCIRuntime::test_deoptimize_call_int);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_throw_and_post_jvmti_exception", address, JVMCIRuntime::throw_and_post_jvmti_exception);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_throw_klass_external_name_exception", address, JVMCIRuntime::throw_klass_external_name_exception);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_throw_class_cast_exception", address, JVMCIRuntime::throw_class_cast_exception);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_vm_message", address, JVMCIRuntime::vm_message);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_vm_error", address, JVMCIRuntime::vm_error);
+}
+
+void AOTCodeHeap::link_shared_runtime_symbols() {
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_resolve_static_entry", address, SharedRuntime::get_resolve_static_call_stub());
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_resolve_virtual_entry", address, SharedRuntime::get_resolve_virtual_call_stub());
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_resolve_opt_virtual_entry", address, SharedRuntime::get_resolve_opt_virtual_call_stub());
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_deopt_blob_unpack", address, SharedRuntime::deopt_blob()->unpack());
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_deopt_blob_unpack_with_exception_in_tls", address, SharedRuntime::deopt_blob()->unpack_with_exception_in_tls());
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_deopt_blob_uncommon_trap", address, SharedRuntime::deopt_blob()->uncommon_trap());
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_ic_miss_stub", address, SharedRuntime::get_ic_miss_stub());
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_handle_wrong_method_stub", address, SharedRuntime::get_handle_wrong_method_stub());
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_exception_handler_for_return_address", address, SharedRuntime::exception_handler_for_return_address);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_register_finalizer", address, SharedRuntime::register_finalizer);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_object_notify", address, JVMCIRuntime::object_notify);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_object_notifyAll", address, JVMCIRuntime::object_notifyAll);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_OSR_migration_end", address, SharedRuntime::OSR_migration_end);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_enable_stack_reserved_zone", address, SharedRuntime::enable_stack_reserved_zone);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_dynamic_invoke", address, CompilerRuntime::resolve_dynamic_invoke);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_string_by_symbol", address, CompilerRuntime::resolve_string_by_symbol);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_klass_by_symbol", address, CompilerRuntime::resolve_klass_by_symbol);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_method_by_symbol_and_load_counters", address, CompilerRuntime::resolve_method_by_symbol_and_load_counters);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_initialize_klass_by_symbol", address, CompilerRuntime::initialize_klass_by_symbol);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_invocation_event", address, CompilerRuntime::invocation_event);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_backedge_event", address, CompilerRuntime::backedge_event);
+
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_shared_runtime_dpow", address, SharedRuntime::dpow);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_shared_runtime_dexp", address, SharedRuntime::dexp);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_shared_runtime_dcos", address, SharedRuntime::dcos);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_shared_runtime_dsin", address, SharedRuntime::dsin);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_shared_runtime_dtan", address, SharedRuntime::dtan);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_shared_runtime_dlog", address, SharedRuntime::dlog);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_shared_runtime_dlog10", address, SharedRuntime::dlog10);
+}
+
+void AOTCodeHeap::link_stub_routines_symbols() {
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_jbyte_arraycopy", address, StubRoutines::_jbyte_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_jshort_arraycopy", address, StubRoutines::_jshort_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_jint_arraycopy", address, StubRoutines::_jint_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_jlong_arraycopy", address, StubRoutines::_jlong_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_oop_arraycopy", address, StubRoutines::_oop_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_oop_arraycopy_uninit", address, StubRoutines::_oop_arraycopy_uninit);
+
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_jbyte_disjoint_arraycopy", address, StubRoutines::_jbyte_disjoint_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_jshort_disjoint_arraycopy", address, StubRoutines::_jshort_disjoint_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_jint_disjoint_arraycopy", address, StubRoutines::_jint_disjoint_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_jlong_disjoint_arraycopy", address, StubRoutines::_jlong_disjoint_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_oop_disjoint_arraycopy", address, StubRoutines::_oop_disjoint_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_oop_disjoint_arraycopy_uninit", address, StubRoutines::_oop_disjoint_arraycopy_uninit);
+
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_jbyte_arraycopy", address, StubRoutines::_arrayof_jbyte_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_jshort_arraycopy", address, StubRoutines::_arrayof_jshort_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_jint_arraycopy", address, StubRoutines::_arrayof_jint_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_jlong_arraycopy", address, StubRoutines::_arrayof_jlong_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_arraycopy", address, StubRoutines::_arrayof_oop_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_arraycopy_uninit", address, StubRoutines::_arrayof_oop_arraycopy_uninit);
+
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_jbyte_disjoint_arraycopy", address, StubRoutines::_arrayof_jbyte_disjoint_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_jshort_disjoint_arraycopy", address, StubRoutines::_arrayof_jshort_disjoint_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_jint_disjoint_arraycopy", address, StubRoutines::_arrayof_jint_disjoint_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_jlong_disjoint_arraycopy", address, StubRoutines::_arrayof_jlong_disjoint_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_disjoint_arraycopy", address, StubRoutines::_arrayof_oop_disjoint_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit", address, StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit);
+
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_unsafe_arraycopy", address, StubRoutines::_unsafe_arraycopy);
+
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_checkcast_arraycopy", address, StubRoutines::_checkcast_arraycopy);
+
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_generic_arraycopy", address, StubRoutines::_generic_arraycopy);
+
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_aescrypt_encryptBlock", address, StubRoutines::_aescrypt_encryptBlock);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_aescrypt_decryptBlock", address, StubRoutines::_aescrypt_decryptBlock);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_cipherBlockChaining_encryptAESCrypt", address, StubRoutines::_cipherBlockChaining_encryptAESCrypt);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_cipherBlockChaining_decryptAESCrypt", address, StubRoutines::_cipherBlockChaining_decryptAESCrypt);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_electronicCodeBook_encryptAESCrypt", address, StubRoutines::_electronicCodeBook_encryptAESCrypt);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_electronicCodeBook_decryptAESCrypt", address, StubRoutines::_electronicCodeBook_decryptAESCrypt);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_update_bytes_crc32", address, StubRoutines::_updateBytesCRC32);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_crc_table_adr", address, StubRoutines::_crc_table_adr);
+
+
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_sha1_implCompress", address, StubRoutines::_sha1_implCompress);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_sha1_implCompressMB", address, StubRoutines::_sha1_implCompressMB);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_sha256_implCompress", address, StubRoutines::_sha256_implCompress);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_sha256_implCompressMB", address, StubRoutines::_sha256_implCompressMB);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_sha512_implCompress", address, StubRoutines::_sha512_implCompress);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_sha512_implCompressMB", address, StubRoutines::_sha512_implCompressMB);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_multiplyToLen", address, StubRoutines::_multiplyToLen);
+
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_counterMode_AESCrypt", address, StubRoutines::_counterMode_AESCrypt);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_ghash_processBlocks", address, StubRoutines::_ghash_processBlocks);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_base64_encodeBlock", address, StubRoutines::_base64_encodeBlock);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_crc32c_table_addr", address, StubRoutines::_crc32c_table_addr);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_updateBytesCRC32C", address, StubRoutines::_updateBytesCRC32C);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_updateBytesAdler32", address, StubRoutines::_updateBytesAdler32);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_squareToLen", address, StubRoutines::_squareToLen);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_mulAdd", address, StubRoutines::_mulAdd);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_montgomeryMultiply", address, StubRoutines::_montgomeryMultiply);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_montgomerySquare", address, StubRoutines::_montgomerySquare);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_vectorizedMismatch", address, StubRoutines::_vectorizedMismatch);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_bigIntegerRightShiftWorker", address, StubRoutines::_bigIntegerRightShiftWorker);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_bigIntegerLeftShiftWorker", address, StubRoutines::_bigIntegerLeftShiftWorker);
+
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_throw_delayed_StackOverflowError_entry", address, StubRoutines::_throw_delayed_StackOverflowError_entry);
+
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_verify_oops", intptr_t, VerifyOops);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_verify_oop_count_address", jint *, &StubRoutines::_verify_oop_count);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_verify_oop_bits", intptr_t, Universe::verify_oop_bits());
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_verify_oop_mask", intptr_t, Universe::verify_oop_mask());
+}
+
+void AOTCodeHeap::link_os_symbols() {
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_os_javaTimeMillis", address, os::javaTimeMillis);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_os_javaTimeNanos", address, os::javaTimeNanos);
+}
+
+/*
+ * Link any global symbols in precompiled DSO with dlopen() _dl_handle
+ * dso_handle.
+ */
+
+void AOTCodeHeap::link_global_lib_symbols() {
+ if (!_lib_symbols_initialized) {
+ _lib_symbols_initialized = true;
+
+ CollectedHeap* heap = Universe::heap();
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_card_table_address", address, (BarrierSet::barrier_set()->is_a(BarrierSet::CardTableBarrierSet) ? ci_card_table_address() : NULL));
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_heap_top_address", address, (heap->supports_inline_contig_alloc() ? heap->top_addr() : NULL));
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_heap_end_address", address, (heap->supports_inline_contig_alloc() ? heap->end_addr() : NULL));
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_klass_base_address", address, CompressedKlassPointers::base());
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_oop_base_address", address, CompressedOops::base());
+#if INCLUDE_G1GC
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_log_of_heap_region_grain_bytes", int, HeapRegion::LogOfHRGrainBytes);
+#endif
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_inline_contiguous_allocation_supported", bool, heap->supports_inline_contig_alloc());
+ link_shared_runtime_symbols();
+ link_stub_routines_symbols();
+ link_os_symbols();
+ link_graal_runtime_symbols();
+ link_known_klasses();
+ }
+}
+
+#ifndef PRODUCT
+int AOTCodeHeap::klasses_seen = 0;
+int AOTCodeHeap::aot_klasses_found = 0;
+int AOTCodeHeap::aot_klasses_fp_miss = 0;
+int AOTCodeHeap::aot_klasses_cl_miss = 0;
+int AOTCodeHeap::aot_methods_found = 0;
+
+void AOTCodeHeap::print_statistics() {
+ tty->print_cr("Classes seen: %d AOT classes found: %d AOT methods found: %d", klasses_seen, aot_klasses_found, aot_methods_found);
+ tty->print_cr("AOT fingerprint mismatches: %d AOT class loader mismatches: %d", aot_klasses_fp_miss, aot_klasses_cl_miss);
+}
+#endif
+
+Method* AOTCodeHeap::find_method(Klass* klass, TRAPS, const char* method_name) {
+ int method_name_len = Bytes::get_Java_u2((address)method_name);
+ method_name += 2;
+ const char* signature_name = method_name + method_name_len;
+ int signature_name_len = Bytes::get_Java_u2((address)signature_name);
+ signature_name += 2;
+ // The class should have been loaded so the method and signature should already be
+ // in the symbol table. If they're not there, the method doesn't exist.
+ TempNewSymbol name = SymbolTable::probe(method_name, method_name_len);
+ TempNewSymbol signature = SymbolTable::probe(signature_name, signature_name_len);
+
+ Method* m;
+ if (name == NULL || signature == NULL) {
+ m = NULL;
+ } else if (name == vmSymbols::object_initializer_name() ||
+ name == vmSymbols::class_initializer_name()) {
+ // Never search superclasses for constructors
+ if (klass->is_instance_klass()) {
+ m = InstanceKlass::cast(klass)->find_method(name, signature);
+ } else {
+ m = NULL;
+ }
+ } else {
+ m = klass->lookup_method(name, signature);
+ if (m == NULL && klass->is_instance_klass()) {
+ m = InstanceKlass::cast(klass)->lookup_method_in_ordered_interfaces(name, signature);
+ }
+ }
+ if (m == NULL) {
+ // Fatal error because we assume classes and methods should not be changed since aot compilation.
+ const char* klass_name = klass->external_name();
+ int klass_len = (int)strlen(klass_name);
+ char* meta_name = NEW_RESOURCE_ARRAY(char, klass_len + 1 + method_name_len + signature_name_len + 1);
+ memcpy(meta_name, klass_name, klass_len);
+ meta_name[klass_len] = '.';
+ memcpy(&meta_name[klass_len + 1], method_name, method_name_len);
+ memcpy(&meta_name[klass_len + 1 + method_name_len], signature_name, signature_name_len);
+ meta_name[klass_len + 1 + method_name_len + signature_name_len] = '\0';
+ Handle exception = Exceptions::new_exception(THREAD, vmSymbols::java_lang_NoSuchMethodError(), meta_name);
+ java_lang_Throwable::print(exception(), tty);
+ tty->cr();
+ java_lang_Throwable::print_stack_trace(exception, tty);
+ tty->cr();
+ fatal("Failed to find method '%s'", meta_name);
+ }
+ NOT_PRODUCT( aot_methods_found++; )
+ return m;
+}
+
+AOTKlassData* AOTCodeHeap::find_klass(const char *name) {
+ return (AOTKlassData*) os::dll_lookup(_lib->dl_handle(), name);
+}
+
+AOTKlassData* AOTCodeHeap::find_klass(InstanceKlass* ik) {
+ ResourceMark rm;
+ AOTKlassData* klass_data = find_klass(ik->signature_name());
+ return klass_data;
+}
+
+bool AOTCodeHeap::is_dependent_method(Klass* dependee, AOTCompiledMethod* aot) {
+ InstanceKlass *dependee_ik = InstanceKlass::cast(dependee);
+ AOTKlassData* klass_data = find_klass(dependee_ik);
+ if (klass_data == NULL) {
+ return false; // no AOT records for this class - no dependencies
+ }
+ if (!dependee_ik->has_passed_fingerprint_check()) {
+ return false; // different class
+ }
+
+ int methods_offset = klass_data->_dependent_methods_offset;
+ if (methods_offset >= 0) {
+ address methods_cnt_adr = _dependencies + methods_offset;
+ int methods_cnt = *(int*)methods_cnt_adr;
+ int* indexes = (int*)(methods_cnt_adr + 4);
+ for (int i = 0; i < methods_cnt; ++i) {
+ int code_id = indexes[i];
+ if (_code_to_aot[code_id]._aot == aot) {
+ return true; // found dependent method
+ }
+ }
+ }
+ return false;
+}
+
+void AOTCodeHeap::mark_evol_dependent_methods(InstanceKlass* dependee) {
+ AOTKlassData* klass_data = find_klass(dependee);
+ if (klass_data == NULL) {
+ return; // no AOT records for this class - no dependencies
+ }
+ if (!dependee->has_passed_fingerprint_check()) {
+ return; // different class
+ }
+
+ int methods_offset = klass_data->_dependent_methods_offset;
+ if (methods_offset >= 0) {
+ address methods_cnt_adr = _dependencies + methods_offset;
+ int methods_cnt = *(int*)methods_cnt_adr;
+ int* indexes = (int*)(methods_cnt_adr + 4);
+ for (int i = 0; i < methods_cnt; ++i) {
+ int code_id = indexes[i];
+ AOTCompiledMethod* aot = _code_to_aot[code_id]._aot;
+ if (aot != NULL) {
+ aot->mark_for_deoptimization(false);
+ }
+ }
+ }
+}
+
+void AOTCodeHeap::sweep_dependent_methods(int* indexes, int methods_cnt) {
+ int marked = 0;
+ for (int i = 0; i < methods_cnt; ++i) {
+ int code_id = indexes[i];
+ // Invalidate aot code.
+ if (Atomic::cmpxchg(&_code_to_aot[code_id]._state, not_set, invalid) != not_set) {
+ if (_code_to_aot[code_id]._state == in_use) {
+ AOTCompiledMethod* aot = _code_to_aot[code_id]._aot;
+ assert(aot != NULL, "aot should be set");
+ if (!aot->is_runtime_stub()) { // Something is wrong - should not invalidate stubs.
+ aot->mark_for_deoptimization(false);
+ marked++;
+ }
+ }
+ }
+ }
+ if (marked > 0) {
+ Deoptimization::deoptimize_all_marked();
+ }
+}
+
+void AOTCodeHeap::sweep_dependent_methods(AOTKlassData* klass_data) {
+ // Make dependent methods non_entrant forever.
+ int methods_offset = klass_data->_dependent_methods_offset;
+ if (methods_offset >= 0) {
+ address methods_cnt_adr = _dependencies + methods_offset;
+ int methods_cnt = *(int*)methods_cnt_adr;
+ int* indexes = (int*)(methods_cnt_adr + 4);
+ sweep_dependent_methods(indexes, methods_cnt);
+ }
+}
+
+void AOTCodeHeap::sweep_dependent_methods(InstanceKlass* ik) {
+ AOTKlassData* klass_data = find_klass(ik);
+ vmassert(klass_data != NULL, "dependency data missing");
+ sweep_dependent_methods(klass_data);
+}
+
+void AOTCodeHeap::sweep_method(AOTCompiledMethod *aot) {
+ int indexes[] = {aot->method_index()};
+ sweep_dependent_methods(indexes, 1);
+ vmassert(aot->method()->code() != aot COMPILER1_OR_COMPILER2_PRESENT( && aot->method()->aot_code() == NULL), "method still active");
+}
+
+
+bool AOTCodeHeap::load_klass_data(InstanceKlass* ik, TRAPS) {
+ ResourceMark rm;
+
+ NOT_PRODUCT( klasses_seen++; )
+
+ // AOT does not support custom class loaders.
+ ClassLoaderData* cld = ik->class_loader_data();
+ if (!cld->is_builtin_class_loader_data()) {
+ log_trace(aot, class, load)("skip class %s for custom classloader %s (%p) tid=" INTPTR_FORMAT,
+ ik->internal_name(), cld->loader_name(), cld, p2i(THREAD));
+ return false;
+ }
+
+ AOTKlassData* klass_data = find_klass(ik);
+ if (klass_data == NULL) {
+ return false;
+ }
+
+ if (!ik->has_passed_fingerprint_check()) {
+ NOT_PRODUCT( aot_klasses_fp_miss++; )
+ log_trace(aot, class, fingerprint)("class %s%s has bad fingerprint in %s tid=" INTPTR_FORMAT,
+ ik->internal_name(), ik->is_shared() ? " (shared)" : "",
+ _lib->name(), p2i(THREAD));
+ sweep_dependent_methods(klass_data);
+ return false;
+ }
+
+ if (ik->has_been_redefined()) {
+ log_trace(aot, class, load)("class %s%s in %s has been redefined tid=" INTPTR_FORMAT,
+ ik->internal_name(), ik->is_shared() ? " (shared)" : "",
+ _lib->name(), p2i(THREAD));
+ sweep_dependent_methods(klass_data);
+ return false;
+ }
+
+ assert(klass_data->_class_id < _class_count, "invalid class id");
+ AOTClass* aot_class = &_classes[klass_data->_class_id];
+ ClassLoaderData* aot_cld = aot_class->_classloader;
+ if (aot_cld != NULL && aot_cld != cld) {
+ log_trace(aot, class, load)("class %s in %s already loaded for classloader %s (%p) vs %s (%p) tid=" INTPTR_FORMAT,
+ ik->internal_name(), _lib->name(), aot_cld->loader_name(), aot_cld, cld->loader_name(), cld, p2i(THREAD));
+ NOT_PRODUCT( aot_klasses_cl_miss++; )
+ return false;
+ }
+
+ if (_lib->config()->_omitAssertions && JavaAssertions::enabled(ik->name()->as_C_string(), ik->class_loader() == NULL)) {
+ log_trace(aot, class, load)("class %s in %s does not have java assertions in compiled code, but assertions are enabled for this execution.", ik->internal_name(), _lib->name());
+ sweep_dependent_methods(klass_data);
+ return false;
+ }
+
+ NOT_PRODUCT( aot_klasses_found++; )
+
+ log_trace(aot, class, load)("found %s in %s for classloader %s (%p) tid=" INTPTR_FORMAT, ik->internal_name(), _lib->name(), cld->loader_name(), cld, p2i(THREAD));
+
+ aot_class->_classloader = cld;
+ // Set klass's Resolve (second) got cell.
+ _klasses_got[klass_data->_got_index] = ik;
+ if (ik->is_initialized()) {
+ _klasses_got[klass_data->_got_index - 1] = ik;
+ }
+
+ // Initialize global symbols of the DSO to the corresponding VM symbol values.
+ link_global_lib_symbols();
+
+ int methods_offset = klass_data->_compiled_methods_offset;
+ if (methods_offset >= 0) {
+ address methods_cnt_adr = _methods_offsets + methods_offset;
+ int methods_cnt = *(int*)methods_cnt_adr;
+ // Collect data about compiled methods
+ AOTMethodData* methods_data = NEW_RESOURCE_ARRAY(AOTMethodData, methods_cnt);
+ AOTMethodOffsets* methods_offsets = (AOTMethodOffsets*)(methods_cnt_adr + 4);
+ for (int i = 0; i < methods_cnt; ++i) {
+ AOTMethodOffsets* method_offsets = &methods_offsets[i];
+ int code_id = method_offsets->_code_id;
+ if (_code_to_aot[code_id]._state == invalid) {
+ continue; // skip AOT methods slots which have been invalidated
+ }
+ AOTMethodData* method_data = &methods_data[i];
+ const char* aot_name = _metaspace_names + method_offsets->_name_offset;
+ method_data->_name = aot_name;
+ method_data->_code = _code_space + method_offsets->_code_offset;
+ method_data->_meta = (aot_metadata*)(_method_metadata + method_offsets->_meta_offset);
+ method_data->_metadata_table = (address)_metadata_got + method_offsets->_metadata_got_offset;
+ method_data->_metadata_size = method_offsets->_metadata_got_size;
+ // aot_name format: "<u2_size>Ljava/lang/ThreadGroup;<u2_size>addUnstarted<u2_size>()V"
+ int klass_len = Bytes::get_Java_u2((address)aot_name);
+ const char* method_name = aot_name + 2 + klass_len;
+ Method* m = AOTCodeHeap::find_method(ik, THREAD, method_name);
+ methodHandle mh(THREAD, m);
+ if (mh->code() != NULL) { // Does it have already compiled code?
+ continue; // Don't overwrite
+ }
+ publish_aot(mh, method_data, code_id);
+ }
+ }
+ return true;
+}
+
+AOTCompiledMethod* AOTCodeHeap::next_in_use_at(int start) const {
+ for (int index = start; index < _method_count; index++) {
+ if (_code_to_aot[index]._state != in_use) {
+ continue; // Skip uninitialized entries.
+ }
+ AOTCompiledMethod* aot = _code_to_aot[index]._aot;
+ return aot;
+ }
+ return NULL;
+}
+
+void* AOTCodeHeap::first() const {
+ return next_in_use_at(0);
+}
+
+void* AOTCodeHeap::next(void* p) const {
+ AOTCompiledMethod *aot = (AOTCompiledMethod *)p;
+ int next_index = aot->method_index() + 1;
+ assert(next_index <= _method_count, "");
+ if (next_index == _method_count) {
+ return NULL;
+ }
+ return next_in_use_at(next_index);
+}
+
+void* AOTCodeHeap::find_start(void* p) const {
+ if (!contains(p)) {
+ return NULL;
+ }
+ size_t offset = pointer_delta(p, low_boundary(), 1);
+ // Use segments table
+ size_t seg_idx = offset / _lib->config()->_codeSegmentSize;
+ if ((int)(_code_segments[seg_idx]) == 0xff) {
+ return NULL;
+ }
+ while (_code_segments[seg_idx] > 0) {
+ seg_idx -= (int)_code_segments[seg_idx];
+ }
+ int code_offset = (int)seg_idx * _lib->config()->_codeSegmentSize;
+ int aot_index = *(int*)(_code_space + code_offset);
+ AOTCompiledMethod* aot = _code_to_aot[aot_index]._aot;
+ assert(aot != NULL, "should find registered aot method");
+ return aot;
+}
+
+AOTCompiledMethod* AOTCodeHeap::find_aot(address p) const {
+ assert(contains(p), "should be here");
+ return (AOTCompiledMethod *)find_start(p);
+}
+
+CodeBlob* AOTCodeHeap::find_blob_unsafe(void* start) const {
+ return (CodeBlob*)AOTCodeHeap::find_start(start);
+}
+
+void AOTCodeHeap::oops_do(OopClosure* f) {
+ for (int i = 0; i < _oop_got_size; i++) {
+ oop* p = &_oop_got[i];
+ if (*p == NULL) continue; // skip non-oops
+ f->do_oop(p);
+ }
+ for (int index = 0; index < _method_count; index++) {
+ if (_code_to_aot[index]._state != in_use) {
+ continue; // Skip uninitialized entries.
+ }
+ AOTCompiledMethod* aot = _code_to_aot[index]._aot;
+ aot->do_oops(f);
+ }
+}
+
+// Scan only klasses_got cells which should have only Klass*,
+// metadata_got cells are scanned only for alive AOT methods
+// by AOTCompiledMethod::metadata_do().
+void AOTCodeHeap::got_metadata_do(MetadataClosure* f) {
+ for (int i = 1; i < _klasses_got_size; i++) {
+ Metadata** p = &_klasses_got[i];
+ Metadata* md = *p;
+ if (md == NULL) continue; // skip non-oops
+ if (Metaspace::contains(md)) {
+ f->do_metadata(md);
+ } else {
+ intptr_t meta = (intptr_t)md;
+ fatal("Invalid value in _klasses_got[%d] = " INTPTR_FORMAT, i, meta);
+ }
+ }
+}
+
+void AOTCodeHeap::cleanup_inline_caches() {
+ for (int index = 0; index < _method_count; index++) {
+ if (_code_to_aot[index]._state != in_use) {
+ continue; // Skip uninitialized entries.
+ }
+ AOTCompiledMethod* aot = _code_to_aot[index]._aot;
+ aot->cleanup_inline_caches(false);
+ }
+}
+
+#ifdef ASSERT
+int AOTCodeHeap::verify_icholder_relocations() {
+ int count = 0;
+ for (int index = 0; index < _method_count; index++) {
+ if (_code_to_aot[index]._state != in_use) {
+ continue; // Skip uninitialized entries.
+ }
+ AOTCompiledMethod* aot = _code_to_aot[index]._aot;
+ count += aot->verify_icholder_relocations();
+ }
+ return count;
+}
+#endif
+
+void AOTCodeHeap::metadata_do(MetadataClosure* f) {
+ for (int index = 0; index < _method_count; index++) {
+ if (_code_to_aot[index]._state != in_use) {
+ continue; // Skip uninitialized entries.
+ }
+ AOTCompiledMethod* aot = _code_to_aot[index]._aot;
+ if (aot->_is_alive()) {
+ aot->metadata_do(f);
+ }
+ }
+ // Scan klasses_got cells.
+ got_metadata_do(f);
+}
+
+bool AOTCodeHeap::reconcile_dynamic_klass(AOTCompiledMethod *caller, InstanceKlass* holder, int index, Klass *dyno_klass, const char *descriptor1, const char *descriptor2) {
+ const char * const descriptors[2] = {descriptor1, descriptor2};
+ JavaThread *thread = JavaThread::current();
+ ResourceMark rm(thread);
+
+ AOTKlassData* holder_data = find_klass(holder);
+ vmassert(holder_data != NULL, "klass %s not found", holder->signature_name());
+ vmassert(is_dependent_method(holder, caller), "sanity");
+
+ AOTKlassData* dyno_data = NULL;
+ bool adapter_failed = false;
+ char buf[64];
+ int descriptor_index = 0;
+ // descriptors[0] specific name ("adapter:<method_id>") for matching
+ // descriptors[1] fall-back name ("adapter") for depdencies
+ while (descriptor_index < 2) {
+ const char *descriptor = descriptors[descriptor_index];
+ if (descriptor == NULL) {
+ break;
+ }
+ jio_snprintf(buf, sizeof buf, "%s<%d:%d>", descriptor, holder_data->_class_id, index);
+ dyno_data = find_klass(buf);
+ if (dyno_data != NULL) {
+ break;
+ }
+ // If match failed then try fall-back for dependencies
+ ++descriptor_index;
+ adapter_failed = true;
+ }
+
+ if (dyno_data == NULL && dyno_klass == NULL) {
+ // all is well, no (appendix) at compile-time, and still none
+ return true;
+ }
+
+ if (dyno_data == NULL) {
+ // no (appendix) at build-time, but now there is
+ sweep_dependent_methods(holder_data);
+ return false;
+ }
+
+ if (adapter_failed) {
+ // adapter method mismatch
+ sweep_dependent_methods(holder_data);
+ sweep_dependent_methods(dyno_data);
+ return false;
+ }
+
+ if (dyno_klass == NULL) {
+ // (appendix) at build-time, none now
+ sweep_dependent_methods(holder_data);
+ sweep_dependent_methods(dyno_data);
+ return false;
+ }
+
+ // TODO: support array appendix object
+ if (!dyno_klass->is_instance_klass()) {
+ sweep_dependent_methods(holder_data);
+ sweep_dependent_methods(dyno_data);
+ return false;
+ }
+
+ InstanceKlass* dyno = InstanceKlass::cast(dyno_klass);
+
+ if (!dyno->is_hidden()) {
+ if (_klasses_got[dyno_data->_got_index] != dyno) {
+ // compile-time class different from runtime class, fail and deoptimize
+ sweep_dependent_methods(holder_data);
+ sweep_dependent_methods(dyno_data);
+ return false;
+ }
+
+ if (dyno->is_initialized()) {
+ _klasses_got[dyno_data->_got_index - 1] = dyno;
+ }
+ return true;
+ }
+
+ // TODO: support anonymous supers
+ if (!dyno->supers_have_passed_fingerprint_checks() || dyno->get_stored_fingerprint() != dyno_data->_fingerprint) {
+ NOT_PRODUCT( aot_klasses_fp_miss++; )
+ log_trace(aot, class, fingerprint)("class %s%s has bad fingerprint in %s tid=" INTPTR_FORMAT,
+ dyno->internal_name(), dyno->is_shared() ? " (shared)" : "",
+ _lib->name(), p2i(thread));
+ sweep_dependent_methods(holder_data);
+ sweep_dependent_methods(dyno_data);
+ return false;
+ }
+
+ _klasses_got[dyno_data->_got_index] = dyno;
+ if (dyno->is_initialized()) {
+ _klasses_got[dyno_data->_got_index - 1] = dyno;
+ }
+
+ // TODO: hook up any AOT code
+ // load_klass_data(dyno_data, thread);
+ return true;
+}
+
+bool AOTCodeHeap::reconcile_dynamic_method(AOTCompiledMethod *caller, InstanceKlass* holder, int index, Method *adapter_method) {
+ InstanceKlass *adapter_klass = adapter_method->method_holder();
+ char buf[64];
+ jio_snprintf(buf, sizeof buf, "adapter:%d", adapter_method->method_idnum());
+ if (!reconcile_dynamic_klass(caller, holder, index, adapter_klass, buf, "adapter")) {
+ return false;
+ }
+ return true;
+}
+
+bool AOTCodeHeap::reconcile_dynamic_invoke(AOTCompiledMethod* caller, InstanceKlass* holder, int index, Method* adapter_method, Klass *appendix_klass) {
+ if (!reconcile_dynamic_klass(caller, holder, index, appendix_klass, "appendix")) {
+ return false;
+ }
+
+ if (!reconcile_dynamic_method(caller, holder, index, adapter_method)) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/hotspot/share/aot/aotCodeHeap.hpp b/src/hotspot/share/aot/aotCodeHeap.hpp
new file mode 100644
index 000000000..40c187ec7
--- /dev/null
+++ b/src/hotspot/share/aot/aotCodeHeap.hpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef SHARE_AOT_AOTCODEHEAP_HPP
+#define SHARE_AOT_AOTCODEHEAP_HPP
+
+#include "aot/aotCompiledMethod.hpp"
+#include "classfile/symbolTable.hpp"
+//#include "metaprogramming/integralConstant.hpp"
+#include "oops/metadata.hpp"
+#include "oops/method.hpp"
+
+enum CodeState {
+ not_set = 0, // _aot fields is not set yet
+ in_use = 1, // _aot field is set to corresponding AOTCompiledMethod
+ invalid = 2 // AOT code is invalidated because dependencies failed
+};
+
+typedef struct {
+ AOTCompiledMethod* _aot;
+ CodeState _state; // State change cases: not_set->in_use, not_set->invalid
+} CodeToAMethod;
+
+class ClassLoaderData;
+
+class AOTClass {
+public:
+ ClassLoaderData* _classloader;
+};
+
+typedef struct {
+ int _name_offset;
+ int _code_offset;
+ int _meta_offset;
+ int _metadata_got_offset;
+ int _metadata_got_size;
+ int _code_id;
+} AOTMethodOffsets;
+
+typedef struct {
+ const char* _name;
+ address _code;
+ aot_metadata* _meta;
+ jlong* _state_adr;
+ address _metadata_table;
+ int _metadata_size;
+} AOTMethodData;
+
+typedef struct {
+ int _got_index;
+ int _class_id;
+ int _compiled_methods_offset;
+ int _dependent_methods_offset;
+ uint64_t _fingerprint;
+} AOTKlassData;
+
+typedef struct {
+ int _version;
+ int _class_count;
+ int _method_count;
+ int _klasses_got_size;
+ int _metadata_got_size;
+ int _oop_got_size;
+ int _jvm_version_offset;
+
+ enum {
+ AOT_SHARED_VERSION = 1
+ };
+} AOTHeader;
+
+typedef struct {
+ enum { CONFIG_SIZE = 7 * jintSize + 9 };
+ // 7 int values
+ int _config_size;
+ int _narrowOopShift;
+ int _narrowKlassShift;
+ int _contendedPaddingWidth;
+ int _objectAlignment;
+ int _codeSegmentSize;
+ int _gc;
+ // byte[9] array map to boolean values here
+ bool _debug_VM;
+ bool _useCompressedOops;
+ bool _useCompressedClassPointers;
+ bool _useTLAB;
+ bool _useBiasedLocking;
+ bool _tieredAOT;
+ bool _enableContended;
+ bool _restrictContended;
+ bool _omitAssertions;
+} AOTConfiguration;
+
+class AOTLib : public CHeapObj<mtCode> {
+ static bool _narrow_oop_shift_initialized;
+ static int _narrow_oop_shift;
+ static int _narrow_klass_shift;
+
+ bool _valid;
+ void* _dl_handle;
+ const int _dso_id;
+ const char* _name;
+ // VM configuration during AOT compilation
+ AOTConfiguration* _config;
+ AOTHeader* _header;
+
+ void handle_config_error(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
+public:
+ AOTLib(void* handle, const char* name, int dso_id);
+ virtual ~AOTLib();
+ static int narrow_oop_shift() { return _narrow_oop_shift; }
+ static int narrow_klass_shift() { return _narrow_klass_shift; }
+ static bool narrow_oop_shift_initialized() { return _narrow_oop_shift_initialized; }
+
+ bool is_valid() const {
+ return _valid;
+ }
+ const char* name() const {
+ return _name;
+ }
+ void* dl_handle() const {
+ return _dl_handle;
+ }
+ int id() const {
+ return _dso_id;
+ }
+ AOTHeader* header() const {
+ return _header;
+ }
+ AOTConfiguration* config() const {
+ return _config;
+ }
+ void verify_config();
+ void verify_flag(bool aot_flag, bool flag, const char* name);
+ void verify_flag(int aot_flag, int flag, const char* name);
+
+ address load_symbol(const char *name);
+};
+
+
+class AOTCodeHeap : public CodeHeap {
+ AOTLib* _lib;
+ int _aot_id;
+
+ int _class_count;
+ int _method_count;
+ AOTClass* _classes;
+ CodeToAMethod* _code_to_aot;
+
+ address _code_space;
+ address _code_segments;
+ jlong* _method_state;
+
+
+ // Collect metaspace info: names -> address in .got section
+ const char* _metaspace_names;
+ address _method_metadata;
+
+ address _methods_offsets;
+ address _klasses_offsets;
+ address _dependencies;
+
+ Metadata** _klasses_got;
+ Metadata** _metadata_got;
+ oop* _oop_got;
+
+ int _klasses_got_size;
+ int _metadata_got_size;
+ int _oop_got_size;
+
+ // Collect stubs info
+ int* _stubs_offsets;
+
+ bool _lib_symbols_initialized;
+
+ void adjust_boundaries(AOTCompiledMethod* method) {
+ char* low = (char*)method->code_begin();
+ if (low < low_boundary()) {
+ _memory.set_low_boundary(low);
+ _memory.set_low(low);
+ }
+ char* high = (char *)method->code_end();
+ if (high > high_boundary()) {
+ _memory.set_high_boundary(high);
+ _memory.set_high(high);
+ }
+ assert(_method_count > 0, "methods count should be set already");
+ }
+
+ void register_stubs();
+
+ void link_shared_runtime_symbols();
+ void link_stub_routines_symbols();
+ void link_os_symbols();
+ void link_graal_runtime_symbols();
+
+ void link_global_lib_symbols();
+ void link_klass(const Klass* klass);
+ void link_known_klasses();
+ void publish_aot(const methodHandle& mh, AOTMethodData* method_data, int code_id);
+
+
+ AOTCompiledMethod* next_in_use_at(int index) const;
+
+ // Find klass in SystemDictionary for aot metadata.
+ static Klass* lookup_klass(const char* name, int len, const Method* method, Thread* THREAD);
+public:
+ AOTCodeHeap(AOTLib* lib);
+ virtual ~AOTCodeHeap();
+
+ AOTCompiledMethod* find_aot(address p) const;
+
+ virtual void* find_start(void* p) const;
+ virtual CodeBlob* find_blob_unsafe(void* start) const;
+ virtual void* first() const;
+ virtual void* next(void *p) const;
+
+ AOTKlassData* find_klass(InstanceKlass* ik);
+ bool load_klass_data(InstanceKlass* ik, TRAPS);
+ Klass* get_klass_from_got(const char* klass_name, int klass_len, const Method* method);
+
+ bool is_dependent_method(Klass* dependee, AOTCompiledMethod* aot);
+ void mark_evol_dependent_methods(InstanceKlass* dependee);
+
+ const char* get_name_at(int offset) {
+ return _metaspace_names + offset;
+ }
+
+
+ void oops_do(OopClosure* f);
+ void metadata_do(MetadataClosure* f);
+ void got_metadata_do(MetadataClosure* f);
+
+#ifdef ASSERT
+ bool got_contains(Metadata **p) {
+ return (p >= &_metadata_got[0] && p < &_metadata_got[_metadata_got_size]) ||
+ (p >= &_klasses_got[0] && p < &_klasses_got[_klasses_got_size]);
+ }
+#endif
+
+ int dso_id() const { return _lib->id(); }
+ int aot_id() const { return _aot_id; }
+
+ int method_count() { return _method_count; }
+
+ AOTCompiledMethod* get_code_desc_at_index(int index) {
+ if (index < _method_count && _code_to_aot[index]._state == in_use) {
+ AOTCompiledMethod* m = _code_to_aot[index]._aot;
+ assert(m != NULL, "AOT method should be set");
+ if (!m->is_runtime_stub()) {
+ return m;
+ }
+ }
+ return NULL;
+ }
+
+ static Method* find_method(Klass* klass, TRAPS, const char* method_name);
+
+ void cleanup_inline_caches();
+
+ DEBUG_ONLY( int verify_icholder_relocations(); )
+
+ void alive_methods_do(void f(CompiledMethod* nm));
+
+#ifndef PRODUCT
+ static int klasses_seen;
+ static int aot_klasses_found;
+ static int aot_klasses_fp_miss;
+ static int aot_klasses_cl_miss;
+ static int aot_methods_found;
+
+ static void print_statistics();
+#endif
+
+ bool reconcile_dynamic_invoke(AOTCompiledMethod* caller, InstanceKlass* holder, int index, Method* adapter_method, Klass *appendix_klass);
+
+private:
+ AOTKlassData* find_klass(const char* name);
+
+ void sweep_dependent_methods(int* indexes, int methods_cnt);
+ void sweep_dependent_methods(AOTKlassData* klass_data);
+ void sweep_dependent_methods(InstanceKlass* ik);
+ void sweep_method(AOTCompiledMethod* aot);
+
+ bool reconcile_dynamic_klass(AOTCompiledMethod *caller, InstanceKlass* holder, int index, Klass *dyno, const char *descriptor1, const char *descriptor2 = NULL);
+
+ bool reconcile_dynamic_method(AOTCompiledMethod *caller, InstanceKlass* holder, int index, Method *adapter_method);
+
+};
+
+#endif // SHARE_AOT_AOTCODEHEAP_HPP
diff --git a/src/hotspot/share/aot/aotCompiledMethod.cpp b/src/hotspot/share/aot/aotCompiledMethod.cpp
new file mode 100644
index 000000000..ec7a501ec
--- /dev/null
+++ b/src/hotspot/share/aot/aotCompiledMethod.cpp
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+
+#include "aot/aotCodeHeap.hpp"
+#include "aot/aotLoader.hpp"
+#include "aot/compiledIC_aot.hpp"
+#include "code/codeCache.hpp"
+#include "code/compiledIC.hpp"
+#include "code/nativeInst.hpp"
+#include "compiler/compilerOracle.hpp"
+#include "gc/shared/cardTableBarrierSet.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "oops/klass.inline.hpp"
+#include "oops/method.inline.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/java.hpp"
+#include "runtime/orderAccess.hpp"
+#include "runtime/os.hpp"
+#include "runtime/safepointVerifiers.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "utilities/sizes.hpp"
+#include "utilities/xmlstream.hpp"
+
+#include <stdio.h>
+
+address* AOTCompiledMethod::orig_pc_addr(const frame* fr) {
+ return (address*) ((address)fr->unextended_sp() + _meta->orig_pc_offset());
+}
+
+oop AOTCompiledMethod::oop_at(int index) const {
+ if (index == 0) { // 0 is reserved
+ return NULL;
+ }
+ Metadata** entry = _metadata_got + (index - 1);
+ intptr_t meta = (intptr_t)*entry;
+ if ((meta & 1) == 1) {
+ // already resolved
+ Klass* k = (Klass*)(meta & ~1);
+ return k->java_mirror();
+ }
+ // The entry is string which we need to resolve.
+ const char* meta_name = _heap->get_name_at((int)meta);
+ int klass_len = Bytes::get_Java_u2((address)meta_name);
+ const char* klass_name = meta_name + 2;
+ // Quick check the current method's holder.
+ Klass* k = _method->method_holder();
+
+ ResourceMark rm; // for signature_name()
+ if (strncmp(k->signature_name(), klass_name, klass_len) != 0) { // Does not match?
+ // Search klass in got cells in DSO which have this compiled method.
+ k = _heap->get_klass_from_got(klass_name, klass_len, _method);
+ }
+ int method_name_len = Bytes::get_Java_u2((address)klass_name + klass_len);
+ guarantee(method_name_len == 0, "only klass is expected here");
+ meta = ((intptr_t)k) | 1;
+ *entry = (Metadata*)meta; // Should be atomic on x64
+ return k->java_mirror();
+}
+
+Metadata* AOTCompiledMethod::metadata_at(int index) const {
+ if (index == 0) { // 0 is reserved
+ return NULL;
+ }
+ assert(index - 1 < _metadata_size, "");
+ {
+ Metadata** entry = _metadata_got + (index - 1);
+ intptr_t meta = (intptr_t)*entry;
+ if ((meta & 1) == 1) {
+ // already resolved
+ Metadata *m = (Metadata*)(meta & ~1);
+ return m;
+ }
+ // The entry is string which we need to resolve.
+ const char* meta_name = _heap->get_name_at((int)meta);
+ int klass_len = Bytes::get_Java_u2((address)meta_name);
+ const char* klass_name = meta_name + 2;
+ // Quick check the current method's holder.
+ Klass* k = _method->method_holder();
+ bool klass_matched = true;
+
+ ResourceMark rm; // for signature_name() and find_method()
+ if (strncmp(k->signature_name(), klass_name, klass_len) != 0) { // Does not match?
+ // Search klass in got cells in DSO which have this compiled method.
+ k = _heap->get_klass_from_got(klass_name, klass_len, _method);
+ klass_matched = false;
+ }
+ int method_name_len = Bytes::get_Java_u2((address)klass_name + klass_len);
+ if (method_name_len == 0) { // Array or Klass name only?
+ meta = ((intptr_t)k) | 1;
+ *entry = (Metadata*)meta; // Should be atomic on x64
+ return (Metadata*)k;
+ } else { // Method
+ // Quick check the current method's name.
+ Method* m = _method;
+ int signature_len = Bytes::get_Java_u2((address)klass_name + klass_len + 2 + method_name_len);
+ int full_len = 2 + klass_len + 2 + method_name_len + 2 + signature_len;
+ if (!klass_matched || memcmp(_name, meta_name, full_len) != 0) { // Does not match?
+ JavaThread* THREAD = JavaThread::current();
+ const char* method_name = klass_name + klass_len;
+ m = AOTCodeHeap::find_method(k, THREAD, method_name);
+ }
+ meta = ((intptr_t)m) | 1;
+ *entry = (Metadata*)meta; // Should be atomic on x64
+ return (Metadata*)m;
+ }
+ }
+ ShouldNotReachHere(); return NULL;
+}
+
+void AOTCompiledMethod::do_unloading(bool unloading_occurred) {
+ unload_nmethod_caches(unloading_occurred);
+}
+
+bool AOTCompiledMethod::make_not_entrant_helper(int new_state) {
+ NoSafepointVerifier nsv;
+
+ {
+ // Enter critical section. Does not block for safepoint.
+ MutexLocker pl(CompiledMethod_lock, Mutex::_no_safepoint_check_flag);
+
+ if (*_state_adr == new_state) {
+ // another thread already performed this transition so nothing
+ // to do, but return false to indicate this.
+ return false;
+ }
+
+ // Change state
+ OrderAccess::storestore();
+ *_state_adr = new_state;
+
+ // Log the transition once
+ log_state_change();
+
+#if COMPILER1_OR_COMPILER2
+ // Remain non-entrant forever
+ if (new_state == not_entrant && method() != NULL) {
+ method()->set_aot_code(NULL);
+ }
+#endif // COMPILER1_OR_COMPILER2
+
+ // Remove AOTCompiledMethod from method.
+ if (method() != NULL) {
+ method()->unlink_code(this);
+ }
+ } // leave critical region under CompiledMethod_lock
+
+
+ if (TraceCreateZombies) {
+ ResourceMark m;
+ const char *new_state_str = (new_state == not_entrant) ? "not entrant" : "not used";
+ tty->print_cr("aot method <" INTPTR_FORMAT "> %s code made %s", p2i(this), this->method() ? this->method()->name_and_sig_as_C_string() : "null", new_state_str);
+ }
+
+ return true;
+}
+
+bool AOTCompiledMethod::make_entrant() {
+#if COMPILER1_OR_COMPILER2
+ assert(!method()->is_old(), "reviving evolved method!");
+
+ NoSafepointVerifier nsv;
+ {
+ // Enter critical section. Does not block for safepoint.
+ MutexLocker pl(CompiledMethod_lock, Mutex::_no_safepoint_check_flag);
+
+ if (*_state_adr == in_use || *_state_adr == not_entrant) {
+ // another thread already performed this transition so nothing
+ // to do, but return false to indicate this.
+ return false;
+ }
+
+ // Change state
+ OrderAccess::storestore();
+ *_state_adr = in_use;
+
+ // Log the transition once
+ log_state_change();
+ } // leave critical region under CompiledMethod_lock
+
+
+ if (TraceCreateZombies) {
+ ResourceMark m;
+ tty->print_cr("aot method <" INTPTR_FORMAT "> %s code made entrant", p2i(this), this->method() ? this->method()->name_and_sig_as_C_string() : "null");
+ }
+
+ return true;
+#else
+ return false;
+#endif // COMPILER1_OR_COMPILER2
+}
+
+// Iterate over metadata calling this function. Used by RedefineClasses
+// Copied from nmethod::metadata_do
+void AOTCompiledMethod::metadata_do(MetadataClosure* f) {
+ address low_boundary = verified_entry_point();
+ {
+ // Visit all immediate references that are embedded in the instruction stream.
+ RelocIterator iter(this, low_boundary);
+ while (iter.next()) {
+ if (iter.type() == relocInfo::metadata_type ) {
+ metadata_Relocation* r = iter.metadata_reloc();
+ // In this metadata, we must only follow those metadatas directly embedded in
+ // the code. Other metadatas (oop_index>0) are seen as part of
+ // the metadata section below.
+ assert(1 == (r->metadata_is_immediate()) +
+ (r->metadata_addr() >= metadata_begin() && r->metadata_addr() < metadata_end()),
+ "metadata must be found in exactly one place");
+ if (r->metadata_is_immediate() && r->metadata_value() != NULL) {
+ Metadata* md = r->metadata_value();
+ if (md != _method) f->do_metadata(md);
+ }
+ } else if (iter.type() == relocInfo::virtual_call_type) {
+ ResourceMark rm;
+ // Check compiledIC holders associated with this nmethod
+ CompiledIC *ic = CompiledIC_at(&iter);
+ if (ic->is_icholder_call()) {
+ CompiledICHolder* cichk = ic->cached_icholder();
+ f->do_metadata(cichk->holder_metadata());
+ f->do_metadata(cichk->holder_klass());
+ } else {
+ // Get Klass* or NULL (if value is -1) from GOT cell of virtual call PLT stub.
+ Metadata* ic_oop = ic->cached_metadata();
+ if (ic_oop != NULL) {
+ f->do_metadata(ic_oop);
+ }
+ }
+ } else if (iter.type() == relocInfo::static_call_type ||
+ iter.type() == relocInfo::opt_virtual_call_type) {
+ // Check Method* in AOT c2i stub for other calls.
+ Metadata* meta = (Metadata*)nativeLoadGot_at(nativePltCall_at(iter.addr())->plt_c2i_stub())->data();
+ if (meta != NULL) {
+ f->do_metadata(meta);
+ }
+ }
+ }
+ }
+
+ // Visit the metadata section
+ for (Metadata** p = metadata_begin(); p < metadata_end(); p++) {
+ Metadata* m = *p;
+
+ intptr_t meta = (intptr_t)m;
+ if ((meta & 1) == 1) {
+ // already resolved
+ m = (Metadata*)(meta & ~1);
+ } else {
+ continue;
+ }
+ assert(Metaspace::contains(m), "");
+ f->do_metadata(m);
+ }
+
+ // Visit metadata not embedded in the other places.
+ if (_method != NULL) f->do_metadata(_method);
+}
+
+void AOTCompiledMethod::print() const {
+ print_on(tty, "AOTCompiledMethod");
+}
+
+void AOTCompiledMethod::print_on(outputStream* st) const {
+ print_on(st, "AOTCompiledMethod");
+}
+
+// Print out more verbose output usually for a newly created aot method.
+void AOTCompiledMethod::print_on(outputStream* st, const char* msg) const {
+ if (st != NULL) {
+ ttyLocker ttyl;
+ st->print("%7d ", (int) tty->time_stamp().milliseconds());
+ st->print("%4d ", _aot_id); // print compilation number
+ st->print(" aot[%2d]", _heap->dso_id());
+ // Stubs have _method == NULL
+ if (_method == NULL) {
+ st->print(" %s", _name);
+ } else {
+ ResourceMark m;
+ st->print(" %s", _method->name_and_sig_as_C_string());
+ }
+ if (Verbose) {
+ st->print(" entry at " INTPTR_FORMAT, p2i(_code));
+ }
+ if (msg != NULL) {
+ st->print(" %s", msg);
+ }
+ st->cr();
+ }
+}
+
+void AOTCompiledMethod::print_value_on(outputStream* st) const {
+ st->print("AOTCompiledMethod ");
+ print_on(st, NULL);
+}
+
+// Print a short set of xml attributes to identify this aot method. The
+// output should be embedded in some other element.
+void AOTCompiledMethod::log_identity(xmlStream* log) const {
+ log->print(" aot_id='%d'", _aot_id);
+ log->print(" aot='%2d'", _heap->dso_id());
+}
+
+void AOTCompiledMethod::log_state_change() const {
+ if (LogCompilation) {
+ ResourceMark m;
+ if (xtty != NULL) {
+ ttyLocker ttyl; // keep the following output all in one block
+ if (*_state_adr == not_entrant) {
+ xtty->begin_elem("make_not_entrant thread='" UINTX_FORMAT "'",
+ os::current_thread_id());
+ } else if (*_state_adr == not_used) {
+ xtty->begin_elem("make_not_used thread='" UINTX_FORMAT "'",
+ os::current_thread_id());
+ } else if (*_state_adr == in_use) {
+ xtty->begin_elem("make_entrant thread='" UINTX_FORMAT "'",
+ os::current_thread_id());
+ }
+ log_identity(xtty);
+ xtty->stamp();
+ xtty->end_elem();
+ }
+ }
+ if (PrintCompilation) {
+ ResourceMark m;
+ if (*_state_adr == not_entrant) {
+ print_on(tty, "made not entrant");
+ } else if (*_state_adr == not_used) {
+ print_on(tty, "made not used");
+ } else if (*_state_adr == in_use) {
+ print_on(tty, "made entrant");
+ }
+ }
+}
+
+
+NativeInstruction* PltNativeCallWrapper::get_load_instruction(virtual_call_Relocation* r) const {
+ return nativeLoadGot_at(_call->plt_load_got());
+}
+
+void PltNativeCallWrapper::verify_resolve_call(address dest) const {
+ CodeBlob* db = CodeCache::find_blob_unsafe(dest);
+ if (db == NULL) {
+ assert(dest == _call->plt_resolve_call(), "sanity");
+ }
+}
+
+void PltNativeCallWrapper::set_to_interpreted(const methodHandle& method, CompiledICInfo& info) {
+ assert(!info.to_aot(), "only for nmethod");
+ CompiledPltStaticCall* csc = CompiledPltStaticCall::at(instruction_address());
+ csc->set_to_interpreted(method, info.entry());
+}
+
+NativeCallWrapper* AOTCompiledMethod::call_wrapper_at(address call) const {
+ return new PltNativeCallWrapper((NativePltCall*) call);
+}
+
+NativeCallWrapper* AOTCompiledMethod::call_wrapper_before(address return_pc) const {
+ return new PltNativeCallWrapper(nativePltCall_before(return_pc));
+}
+
+CompiledStaticCall* AOTCompiledMethod::compiledStaticCall_at(Relocation* call_site) const {
+ return CompiledPltStaticCall::at(call_site);
+}
+
+CompiledStaticCall* AOTCompiledMethod::compiledStaticCall_at(address call_site) const {
+ return CompiledPltStaticCall::at(call_site);
+}
+
+CompiledStaticCall* AOTCompiledMethod::compiledStaticCall_before(address return_addr) const {
+ return CompiledPltStaticCall::before(return_addr);
+}
+
+address AOTCompiledMethod::call_instruction_address(address pc) const {
+ NativePltCall* pltcall = nativePltCall_before(pc);
+ return pltcall->instruction_address();
+}
+
+void AOTCompiledMethod::clear_inline_caches() {
+ assert(SafepointSynchronize::is_at_safepoint(), "cleaning of IC's only allowed at safepoint");
+ if (is_zombie()) {
+ return;
+ }
+
+ ResourceMark rm;
+ RelocIterator iter(this);
+ while (iter.next()) {
+ iter.reloc()->clear_inline_cache();
+ if (iter.type() == relocInfo::opt_virtual_call_type) {
+ CompiledIC* cic = CompiledIC_at(&iter);
+ assert(cic->is_clean(), "!");
+ nativePltCall_at(iter.addr())->set_stub_to_clean();
+ }
+ }
+}
diff --git a/src/hotspot/share/aot/aotCompiledMethod.hpp b/src/hotspot/share/aot/aotCompiledMethod.hpp
new file mode 100644
index 000000000..c9136a36a
--- /dev/null
+++ b/src/hotspot/share/aot/aotCompiledMethod.hpp
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef SHARE_AOT_AOTCOMPILEDMETHOD_HPP
+#define SHARE_AOT_AOTCOMPILEDMETHOD_HPP
+
+#include "code/codeCache.hpp"
+#include "code/compiledIC.hpp"
+#include "code/compiledMethod.hpp"
+#include "code/pcDesc.hpp"
+#include "code/relocInfo.hpp"
+
+class AOTCodeHeap;
+
+class aot_metadata {
+private:
+ int _size;
+ int _code_size;
+ int _entry;
+ int _verified_entry;
+ int _exception_handler_offset;
+ int _deopt_handler_offset;
+ int _deopt_mh_handler_offset;
+ int _stubs_offset;
+ int _frame_size;
+ // location in frame (offset for sp) that deopt can store the original
+ // pc during a deopt.
+ int _orig_pc_offset;
+ int _unsafe_access;
+
+ int _pc_desc_begin;
+ int _scopes_begin;
+ int _reloc_begin;
+ int _exception_table_begin;
+ int _nul_chk_table_begin;
+ int _oopmap_begin;
+ address at_offset(size_t offset) const { return ((address) this) + offset; }
+public:
+ int code_size() const { return _code_size; }
+ int frame_size() const { return _frame_size / HeapWordSize; }
+ PcDesc *scopes_pcs_begin() const { return (PcDesc *) at_offset(_pc_desc_begin); }
+ PcDesc *scopes_pcs_end() const { return (PcDesc *) at_offset(_scopes_begin); }
+ address scopes_data_begin() const { return at_offset(_scopes_begin); }
+ address scopes_data_end() const { return at_offset(_reloc_begin); }
+ relocInfo* relocation_begin() const { return (relocInfo*) at_offset(_reloc_begin); }
+ relocInfo* relocation_end() const { return (relocInfo*) at_offset(_exception_table_begin); }
+ address handler_table_begin () const { return at_offset(_exception_table_begin); }
+ address handler_table_end() const { return at_offset(_nul_chk_table_begin); }
+
+ address nul_chk_table_begin() const { return at_offset(_nul_chk_table_begin); }
+ address nul_chk_table_end() const { return at_offset(_oopmap_begin); }
+
+ ImmutableOopMapSet* oopmap_set() const { return (ImmutableOopMapSet*) at_offset(_oopmap_begin); }
+
+ address consts_begin() const { return at_offset(_size); }
+ address consts_end() const { return at_offset(_size); }
+ int stub_offset() const { return _stubs_offset; }
+ int entry_offset() const { return _entry; }
+ int verified_entry_offset() const { return _verified_entry; }
+ int exception_handler_offset() const { return _exception_handler_offset; }
+ int deopt_handler_offset() const { return _deopt_handler_offset; }
+ int deopt_mh_handler_offset() const { return _deopt_mh_handler_offset; }
+ int orig_pc_offset() const { return _orig_pc_offset; }
+
+ int handler_table_size() const { return handler_table_end() - handler_table_begin(); }
+ int nul_chk_table_size() const { return nul_chk_table_end() - nul_chk_table_begin(); }
+ bool has_unsafe_access() const { return _unsafe_access != 0; }
+
+};
+
+/*
+ * Use this for AOTCompiledMethods since a lot of the fields in CodeBlob gets the same
+ * value when they come from AOT. code_begin == content_begin, etc... */
+class AOTCompiledMethodLayout : public CodeBlobLayout {
+public:
+ AOTCompiledMethodLayout(address code_begin, address code_end, address relocation_begin, address relocation_end) :
+ CodeBlobLayout(
+ code_begin, // code_begin
+ code_end, // code_end
+ code_begin, // content_begin
+ code_end, // content_end
+ code_end, // data_end
+ relocation_begin, // relocation_begin
+ relocation_end
+ ) {
+ }
+};
+
+class AOTCompiledMethod : public CompiledMethod, public CHeapObj<mtCode> {
+private:
+ address _code;
+ aot_metadata* _meta;
+ Metadata** _metadata_got;
+ jlong* _state_adr; // Address of cell to indicate aot method state (in_use or not_entrant)
+ AOTCodeHeap* _heap; // code heap which has this method
+ const char* _name; // For stub: "AOT Stub<name>" for stub,
+ // For nmethod: "<u2_size>Ljava/lang/ThreadGroup;<u2_size>addUnstarted<u2_size>()V"
+ const int _metadata_size; // size of _metadata_got
+ const int _aot_id;
+ const int _method_index;
+ oop _oop; // method()->method_holder()->klass_holder()
+
+ address* orig_pc_addr(const frame* fr);
+ bool make_not_entrant_helper(int new_state);
+
+ public:
+ using CHeapObj<mtCode>::operator new;
+ using CHeapObj<mtCode>::operator delete;
+
+ int method_index() const { return _method_index; }
+ void set_oop(oop o) { _oop = o; }
+
+ AOTCompiledMethod(address code, Method* method, aot_metadata* meta, address metadata_got, int metadata_size, jlong* state_adr, AOTCodeHeap* heap, const char* name, int method_index, int aot_id) :
+ CompiledMethod(method, name, compiler_jvmci, // AOT code is generated by JVMCI compiler
+ AOTCompiledMethodLayout(code, code + meta->code_size(), (address) meta->relocation_begin(), (address) meta->relocation_end()),
+ 0 /* frame_complete_offset */, meta->frame_size() /* frame_size */, meta->oopmap_set(), false /* caller_must_gc_arguments */),
+ _code(code),
+ _meta(meta),
+ _metadata_got((Metadata**) metadata_got),
+ _state_adr(state_adr),
+ _heap(heap),
+ _name(name),
+ _metadata_size(metadata_size),
+ _aot_id(aot_id),
+ _method_index(method_index) {
+
+ _is_far_code = CodeCache::is_far_target(code) ||
+ CodeCache::is_far_target(code + meta->code_size());
+ _exception_cache = NULL;
+
+ _scopes_data_begin = (address) _meta->scopes_data_begin();
+ _deopt_handler_begin = (address) _code + _meta->deopt_handler_offset();
+ if (_meta->deopt_mh_handler_offset() != -1) {
+ _deopt_mh_handler_begin = (address) _code + _meta->deopt_mh_handler_offset();
+ } else {
+ _deopt_mh_handler_begin = (address) this;
+ }
+
+ _pc_desc_container.reset_to(scopes_pcs_begin());
+
+ // Mark the AOTCompiledMethod as in_use
+ *_state_adr = nmethod::in_use;
+ set_has_unsafe_access(_meta->has_unsafe_access());
+ _oop = NULL;
+ }
+
+ virtual bool is_aot() const { return true; }
+ virtual bool is_runtime_stub() const { return is_aot_runtime_stub(); }
+
+ virtual bool is_compiled() const { return !is_aot_runtime_stub(); }
+
+ virtual bool is_locked_by_vm() const { return false; }
+
+ int state() const { return *_state_adr; }
+
+ // Non-virtual for speed
+ bool _is_alive() const { return state() < unloaded; }
+
+ virtual bool is_zombie() const { return state() == zombie; }
+ virtual bool is_unloaded() const { return state() == unloaded; }
+ virtual bool is_not_entrant() const { return state() == not_entrant ||
+ state() == not_used; }
+ virtual bool is_alive() const { return _is_alive(); }
+ virtual bool is_in_use() const { return state() == in_use; }
+
+ virtual bool is_unloading() { return false; }
+
+ address exception_begin() const { return (address) _code + _meta->exception_handler_offset(); }
+
+ virtual const char* name() const { return _name; }
+
+ virtual int compile_id() const { return _aot_id; }
+
+ void print_on(outputStream* st) const;
+ void print_on(outputStream* st, const char* msg) const;
+ void print() const;
+
+ virtual void print_value_on(outputStream *stream) const;
+ virtual void print_block_comment(outputStream *stream, address block_begin) const { }
+ virtual void verify() {}
+
+ virtual int comp_level() const { return CompLevel_aot; }
+ virtual address verified_entry_point() const { return _code + _meta->verified_entry_offset(); }
+ virtual void log_identity(xmlStream* stream) const;
+ virtual void log_state_change() const;
+ virtual bool make_entrant();
+ virtual bool make_not_entrant() { return make_not_entrant_helper(not_entrant); }
+ virtual bool make_not_used() { return make_not_entrant_helper(not_used); }
+ virtual address entry_point() const { return _code + _meta->entry_offset(); }
+ virtual bool make_zombie() { ShouldNotReachHere(); return false; }
+ virtual bool is_osr_method() const { return false; }
+ virtual int osr_entry_bci() const { ShouldNotReachHere(); return -1; }
+ // AOT compiled methods do not get into zombie state
+ virtual bool can_convert_to_zombie() { return false; }
+
+ virtual bool is_dependent_on_method(Method* dependee) { return true; }
+
+ virtual void clear_inline_caches();
+
+ virtual void print_pcs() {}
+
+ virtual address scopes_data_end() const { return _meta->scopes_data_end(); }
+
+ virtual oop oop_at(int index) const;
+ virtual Metadata* metadata_at(int index) const;
+
+ virtual PcDesc* scopes_pcs_begin() const { return _meta->scopes_pcs_begin(); }
+ virtual PcDesc* scopes_pcs_end() const { return _meta->scopes_pcs_end(); }
+
+ virtual address handler_table_begin() const { return _meta->handler_table_begin(); }
+ virtual address handler_table_end() const { return _meta->handler_table_end(); }
+
+ virtual address nul_chk_table_begin() const { return _meta->nul_chk_table_begin(); }
+ virtual address nul_chk_table_end() const { return _meta->nul_chk_table_end(); }
+
+ virtual address consts_begin() const { return _meta->consts_begin(); }
+ virtual address consts_end() const { return _meta->consts_end(); }
+
+ virtual address stub_begin() const { return code_begin() + _meta->stub_offset(); }
+ virtual address stub_end() const { return code_end(); }
+
+ virtual oop* oop_addr_at(int index) const { ShouldNotReachHere(); return NULL; }
+ virtual Metadata** metadata_addr_at(int index) const { ShouldNotReachHere(); return NULL; }
+
+ // Accessor/mutator for the original pc of a frame before a frame was deopted.
+ address get_original_pc(const frame* fr) { return *orig_pc_addr(fr); }
+ void set_original_pc(const frame* fr, address pc) { *orig_pc_addr(fr) = pc; }
+
+ virtual void metadata_do(MetadataClosure* f);
+
+ bool metadata_got_contains(Metadata **p) {
+ return p >= &_metadata_got[0] && p < &_metadata_got[_metadata_size];
+ }
+
+ Metadata** metadata_begin() const { return &_metadata_got[0] ; }
+ Metadata** metadata_end() const { return &_metadata_got[_metadata_size] ; }
+ const char* compile_kind() const { return "AOT"; }
+
+ int get_state() const {
+ return (int) (*_state_adr);
+ }
+
+ // inlined and non-virtual for AOTCodeHeap::oops_do
+ void do_oops(OopClosure* f) {
+ assert(_is_alive(), "");
+ if (_oop != NULL) {
+ f->do_oop(&_oop);
+ }
+ }
+
+ virtual void do_unloading(bool unloading_occurred);
+
+protected:
+ // AOT compiled methods are not flushed
+ void flush() {};
+
+ NativeCallWrapper* call_wrapper_at(address call) const;
+ NativeCallWrapper* call_wrapper_before(address return_pc) const;
+ address call_instruction_address(address pc) const;
+
+ CompiledStaticCall* compiledStaticCall_at(Relocation* call_site) const;
+ CompiledStaticCall* compiledStaticCall_at(address addr) const;
+ CompiledStaticCall* compiledStaticCall_before(address addr) const;
+private:
+ bool is_aot_runtime_stub() const { return _method == NULL; }
+};
+
+class PltNativeCallWrapper: public NativeCallWrapper {
+private:
+ NativePltCall* _call;
+
+public:
+ PltNativeCallWrapper(NativePltCall* call) : _call(call) {}
+
+ virtual address destination() const { return _call->destination(); }
+ virtual address instruction_address() const { return _call->instruction_address(); }
+ virtual address next_instruction_address() const { return _call->next_instruction_address(); }
+ virtual address return_address() const { return _call->return_address(); }
+ virtual address get_resolve_call_stub(bool is_optimized) const { return _call->plt_resolve_call(); }
+ virtual void set_destination_mt_safe(address dest) { _call->set_destination_mt_safe(dest); }
+ virtual void set_to_interpreted(const methodHandle& method, CompiledICInfo& info);
+ virtual void verify() const { _call->verify(); }
+ virtual void verify_resolve_call(address dest) const;
+
+ virtual bool is_call_to_interpreted(address dest) const { return (dest == _call->plt_c2i_stub()); }
+ // TODO: assume for now that patching of aot code (got cell) is safe.
+ virtual bool is_safe_for_patching() const { return true; }
+
+ virtual NativeInstruction* get_load_instruction(virtual_call_Relocation* r) const;
+
+ virtual void *get_data(NativeInstruction* instruction) const {
+ return (void*)((NativeLoadGot*) instruction)->data();
+ }
+
+ virtual void set_data(NativeInstruction* instruction, intptr_t data) {
+ ((NativeLoadGot*) instruction)->set_data(data);
+ }
+};
+
+#endif // SHARE_AOT_AOTCOMPILEDMETHOD_HPP
diff --git a/src/hotspot/share/aot/aotLoader.cpp b/src/hotspot/share/aot/aotLoader.cpp
new file mode 100644
index 000000000..4e12ee95a
--- /dev/null
+++ b/src/hotspot/share/aot/aotLoader.cpp
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+#include "aot/aotCodeHeap.hpp"
+#include "aot/aotLoader.inline.hpp"
+#include "classfile/javaClasses.hpp"
+#include "jvm.h"
+#include "jvmci/jvmci.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/compressedOops.hpp"
+#include "oops/method.hpp"
+#include "prims/jvmtiExport.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/globals_extension.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/os.inline.hpp"
+#include "runtime/registerMap.hpp"
+#include "runtime/timerTrace.hpp"
+
+GrowableArray<AOTCodeHeap*>* AOTLoader::_heaps = new(ResourceObj::C_HEAP, mtCode) GrowableArray<AOTCodeHeap*> (2, mtCode);
+GrowableArray<AOTLib*>* AOTLoader::_libraries = new(ResourceObj::C_HEAP, mtCode) GrowableArray<AOTLib*> (2, mtCode);
+
+// Iterate over all AOT CodeHeaps
+#define FOR_ALL_AOT_HEAPS(heap) for (GrowableArrayIterator<AOTCodeHeap*> heap = heaps()->begin(); heap != heaps()->end(); ++heap)
+// Iterate over all AOT Libraries
+#define FOR_ALL_AOT_LIBRARIES(lib) for (GrowableArrayIterator<AOTLib*> lib = libraries()->begin(); lib != libraries()->end(); ++lib)
+
+void AOTLoader::load_for_klass(InstanceKlass* ik, TRAPS) {
+ if (ik->is_hidden()) {
+ // don't even bother
+ return;
+ }
+ if (UseAOT) {
+ // We allow hotswap to be enabled after the onload phase, but not breakpoints
+ assert(!JvmtiExport::can_post_breakpoint(), "AOT should have been disabled.");
+ FOR_ALL_AOT_HEAPS(heap) {
+ (*heap)->load_klass_data(ik, THREAD);
+ }
+ }
+}
+
+uint64_t AOTLoader::get_saved_fingerprint(InstanceKlass* ik) {
+ assert(UseAOT, "called only when AOT is enabled");
+ if (ik->is_hidden()) {
+ // don't even bother
+ return 0;
+ }
+ FOR_ALL_AOT_HEAPS(heap) {
+ AOTKlassData* klass_data = (*heap)->find_klass(ik);
+ if (klass_data != NULL) {
+ return klass_data->_fingerprint;
+ }
+ }
+ return 0;
+}
+
+void AOTLoader::oops_do(OopClosure* f) {
+ if (UseAOT) {
+ FOR_ALL_AOT_HEAPS(heap) {
+ (*heap)->oops_do(f);
+ }
+ }
+}
+
+void AOTLoader::metadata_do(MetadataClosure* f) {
+ if (UseAOT) {
+ FOR_ALL_AOT_HEAPS(heap) {
+ (*heap)->metadata_do(f);
+ }
+ }
+}
+
+void AOTLoader::mark_evol_dependent_methods(InstanceKlass* dependee) {
+ if (UseAOT) {
+ FOR_ALL_AOT_HEAPS(heap) {
+ (*heap)->mark_evol_dependent_methods(dependee);
+ }
+ }
+}
+
+/**
+ * List of core modules for which we search for shared libraries.
+ */
+static const char* modules[] = {
+ "java.base",
+ "java.logging",
+ "jdk.compiler",
+ "jdk.internal.vm.ci",
+ "jdk.internal.vm.compiler"
+};
+
+void AOTLoader::initialize() {
+ TraceTime timer("AOT initialization", TRACETIME_LOG(Info, aot, startuptime));
+
+ if (FLAG_IS_DEFAULT(UseAOT) && AOTLibrary != NULL) {
+ // Don't need to set UseAOT on command line when AOTLibrary is specified
+ FLAG_SET_DEFAULT(UseAOT, true);
+ }
+ if (UseAOT) {
+ // EagerInitialization is not compatible with AOT
+ if (EagerInitialization) {
+ if (PrintAOT) {
+ warning("EagerInitialization is not compatible with AOT (switching AOT off)");
+ }
+ FLAG_SET_DEFAULT(UseAOT, false);
+ return;
+ }
+
+ if (JvmtiExport::can_post_breakpoint()) {
+ if (PrintAOT) {
+ warning("JVMTI capability to post breakpoint is not compatible with AOT (switching AOT off)");
+ }
+ FLAG_SET_DEFAULT(UseAOT, false);
+ return;
+ }
+
+ // -Xint is not compatible with AOT
+ if (Arguments::is_interpreter_only()) {
+ if (PrintAOT) {
+ warning("-Xint is not compatible with AOT (switching AOT off)");
+ }
+ FLAG_SET_DEFAULT(UseAOT, false);
+ return;
+ }
+
+#ifdef _WINDOWS
+ const char pathSep = ';';
+#else
+ const char pathSep = ':';
+#endif
+
+ // Scan the AOTLibrary option.
+ if (AOTLibrary != NULL) {
+ const int len = (int)strlen(AOTLibrary);
+ char* cp = NEW_C_HEAP_ARRAY(char, len+1, mtCode);
+ memcpy(cp, AOTLibrary, len);
+ cp[len] = '\0';
+ char* end = cp + len;
+ while (cp < end) {
+ const char* name = cp;
+ while ((*cp) != '\0' && (*cp) != '\n' && (*cp) != ',' && (*cp) != pathSep) cp++;
+ cp[0] = '\0'; // Terminate name
+ cp++;
+ load_library(name, true);
+ }
+ }
+
+ // Load well-know AOT libraries from Java installation directory.
+ const char* home = Arguments::get_java_home();
+ const char* file_separator = os::file_separator();
+
+ for (int i = 0; i < (int) (sizeof(modules) / sizeof(const char*)); i++) {
+ char library[JVM_MAXPATHLEN];
+ jio_snprintf(library, sizeof(library), "%s%slib%slib%s%s%s%s", home, file_separator, file_separator, modules[i], UseCompressedOops ? "-coop" : "", UseG1GC ? "" : "-nong1", os::dll_file_extension());
+ load_library(library, false);
+ }
+ }
+}
+
+void AOTLoader::universe_init() {
+ if (UseAOT && libraries_count() > 0) {
+ // Shifts are static values which initialized by 0 until java heap initialization.
+ // AOT libs are loaded before heap initialized so shift values are not set.
+ // It is okay since ObjectAlignmentInBytes flag which defines shifts value is set before AOT libs are loaded.
+ // AOT sets shift values during heap and metaspace initialization.
+ // Check shifts value to make sure thay did not change.
+ if (UseCompressedOops && AOTLib::narrow_oop_shift_initialized()) {
+ int oop_shift = CompressedOops::shift();
+ FOR_ALL_AOT_LIBRARIES(lib) {
+ (*lib)->verify_flag((*lib)->config()->_narrowOopShift, oop_shift, "CompressedOops::shift");
+ }
+ if (UseCompressedClassPointers) { // It is set only if UseCompressedOops is set
+ int klass_shift = CompressedKlassPointers::shift();
+ FOR_ALL_AOT_LIBRARIES(lib) {
+ (*lib)->verify_flag((*lib)->config()->_narrowKlassShift, klass_shift, "CompressedKlassPointers::shift");
+ }
+ }
+ }
+ // Create heaps for all valid libraries
+ FOR_ALL_AOT_LIBRARIES(lib) {
+ if ((*lib)->is_valid()) {
+ AOTCodeHeap* heap = new AOTCodeHeap(*lib);
+ {
+ MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+ add_heap(heap);
+ CodeCache::add_heap(heap);
+ }
+ } else {
+ // Unload invalid libraries
+ os::dll_unload((*lib)->dl_handle());
+ }
+ }
+ }
+ if (heaps_count() == 0) {
+ if (FLAG_IS_DEFAULT(UseAOT)) {
+ FLAG_SET_DEFAULT(UseAOT, false);
+ }
+ }
+}
+
+// Set shift value for compressed oops and classes based on first AOT library config.
+// AOTLoader::universe_init(), which is called later, will check the shift value again to make sure nobody change it.
+// This code is not executed during CDS dump because it runs in Interpreter mode and AOT is disabled in this mode.
+
+void AOTLoader::set_narrow_oop_shift() {
+ // This method is called from Universe::initialize_heap().
+ if (UseAOT && libraries_count() > 0 &&
+ UseCompressedOops && AOTLib::narrow_oop_shift_initialized()) {
+ if (CompressedOops::shift() == 0) {
+ // 0 is valid shift value for small heap but we can safely increase it
+ // at this point when nobody used it yet.
+ CompressedOops::set_shift(AOTLib::narrow_oop_shift());
+ }
+ }
+}
+
+void AOTLoader::set_narrow_klass_shift() {
+ // This method is called from Metaspace::set_narrow_klass_base_and_shift().
+ if (UseAOT && libraries_count() > 0 &&
+ UseCompressedOops && AOTLib::narrow_oop_shift_initialized() &&
+ UseCompressedClassPointers) {
+ if (CompressedKlassPointers::shift() == 0) {
+ CompressedKlassPointers::set_shift(AOTLib::narrow_klass_shift());
+ }
+ }
+}
+
+void AOTLoader::load_library(const char* name, bool exit_on_error) {
+ // Skip library if a library with the same name is already loaded.
+ const int file_separator = *os::file_separator();
+ const char* start = strrchr(name, file_separator);
+ const char* new_name = (start == NULL) ? name : (start + 1);
+ FOR_ALL_AOT_LIBRARIES(lib) {
+ const char* lib_name = (*lib)->name();
+ start = strrchr(lib_name, file_separator);
+ const char* old_name = (start == NULL) ? lib_name : (start + 1);
+ if (strcmp(old_name, new_name) == 0) {
+ if (PrintAOT) {
+ warning("AOT library %s is already loaded as %s.", name, lib_name);
+ }
+ return;
+ }
+ }
+ char ebuf[1024];
+ void* handle = os::dll_load(name, ebuf, sizeof ebuf);
+ if (handle == NULL) {
+ if (exit_on_error) {
+ tty->print_cr("error opening file: %s", ebuf);
+ vm_exit(1);
+ }
+ return;
+ }
+ const int dso_id = libraries_count() + 1;
+ AOTLib* lib = new AOTLib(handle, name, dso_id);
+ if (!lib->is_valid()) {
+ delete lib;
+ os::dll_unload(handle);
+ return;
+ }
+ add_library(lib);
+}
+
+#ifndef PRODUCT
+void AOTLoader::print_statistics() {
+ { ttyLocker ttyl;
+ tty->print_cr("--- AOT Statistics ---");
+ tty->print_cr("AOT libraries loaded: %d", heaps_count());
+ AOTCodeHeap::print_statistics();
+ }
+}
+#endif
+
+
+bool AOTLoader::reconcile_dynamic_invoke(InstanceKlass* holder, int index, Method* adapter_method, Klass* appendix_klass) {
+ if (!UseAOT) {
+ return true;
+ }
+ JavaThread* thread = JavaThread::current();
+ ResourceMark rm(thread);
+ RegisterMap map(thread, false);
+ frame caller_frame = thread->last_frame().sender(&map); // Skip stub
+ CodeBlob* caller_cb = caller_frame.cb();
+ guarantee(caller_cb != NULL && caller_cb->is_compiled(), "must be called from compiled method");
+ CompiledMethod* cm = caller_cb->as_compiled_method();
+
+ if (!cm->is_aot()) {
+ return true;
+ }
+ AOTCompiledMethod* aot = (AOTCompiledMethod*)cm;
+
+ AOTCodeHeap* caller_heap = NULL;
+ FOR_ALL_AOT_HEAPS(heap) {
+ if ((*heap)->contains_blob(aot)) {
+ caller_heap = *heap;
+ break;
+ }
+ }
+ guarantee(caller_heap != NULL, "CodeHeap not found");
+ bool success = caller_heap->reconcile_dynamic_invoke(aot, holder, index, adapter_method, appendix_klass);
+ vmassert(success || thread->last_frame().sender(&map).is_deoptimized_frame(), "caller not deoptimized on failure");
+ return success;
+}
+
+
+// This should be called very early during startup before any of the AOTed methods that use boxes can deoptimize.
+// Deoptimization machinery expects the caches to be present and populated.
+void AOTLoader::initialize_box_caches(TRAPS) {
+ if (!UseAOT || libraries_count() == 0) {
+ return;
+ }
+ TraceTime timer("AOT initialization of box caches", TRACETIME_LOG(Info, aot, startuptime));
+ JVMCI::ensure_box_caches_initialized(CHECK);
+}
diff --git a/src/hotspot/share/aot/aotLoader.hpp b/src/hotspot/share/aot/aotLoader.hpp
new file mode 100644
index 000000000..cf03ea087
--- /dev/null
+++ b/src/hotspot/share/aot/aotLoader.hpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef SHARE_AOT_AOTLOADER_HPP
+#define SHARE_AOT_AOTLOADER_HPP
+
+#include "runtime/globals_extension.hpp"
+#include "runtime/handles.hpp"
+
+class AOTCodeHeap;
+class AOTCompiledMethod;
+class AOTLib;
+class CodeBlob;
+template <class T> class GrowableArray;
+class InstanceKlass;
+class JavaThread;
+class Metadata;
+class OopClosure;
+
+class AOTLoader {
+private:
+#if INCLUDE_AOT
+ static GrowableArray<AOTCodeHeap*>* _heaps;
+ static GrowableArray<AOTLib*>* _libraries;
+#endif
+ static void load_library(const char* name, bool exit_on_error);
+
+public:
+#if INCLUDE_AOT
+ static GrowableArray<AOTCodeHeap*>* heaps();
+ static GrowableArray<AOTLib*>* libraries();
+ static int heaps_count();
+ static int libraries_count();
+ static void add_heap(AOTCodeHeap *heap);
+ static void add_library(AOTLib *lib);
+#endif
+ static void initialize() NOT_AOT({ FLAG_SET_ERGO(UseAOT, false); });
+
+ static void universe_init() NOT_AOT_RETURN;
+ static void set_narrow_oop_shift() NOT_AOT_RETURN;
+ static void set_narrow_klass_shift() NOT_AOT_RETURN;
+ static void load_for_klass(InstanceKlass* ik, TRAPS) NOT_AOT_RETURN;
+ static uint64_t get_saved_fingerprint(InstanceKlass* ik) NOT_AOT({ return 0; });
+ static void oops_do(OopClosure* f) NOT_AOT_RETURN;
+ static void metadata_do(MetadataClosure* f) NOT_AOT_RETURN;
+ static void mark_evol_dependent_methods(InstanceKlass* dependee) NOT_AOT_RETURN;
+ static void initialize_box_caches(TRAPS) NOT_AOT_RETURN;
+
+ NOT_PRODUCT( static void print_statistics() NOT_AOT_RETURN; )
+
+ static bool reconcile_dynamic_invoke(InstanceKlass* holder, int index, Method* adapter_method, Klass *appendix_klass) NOT_AOT({ return true; });
+};
+
+#endif // SHARE_AOT_AOTLOADER_HPP
diff --git a/src/hotspot/share/aot/aotLoader.inline.hpp b/src/hotspot/share/aot/aotLoader.inline.hpp
new file mode 100644
index 000000000..708634940
--- /dev/null
+++ b/src/hotspot/share/aot/aotLoader.inline.hpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef SHARE_AOT_AOTLOADER_INLINE_HPP
+#define SHARE_AOT_AOTLOADER_INLINE_HPP
+
+#include "aot/aotLoader.hpp"
+#include "utilities/growableArray.hpp"
+
+#if INCLUDE_AOT
+GrowableArray<AOTCodeHeap*>* AOTLoader::heaps() { return _heaps; }
+GrowableArray<AOTLib*>* AOTLoader::libraries() { return _libraries; }
+int AOTLoader::heaps_count() { return heaps()->length(); }
+int AOTLoader::libraries_count() { return libraries()->length(); }
+void AOTLoader::add_heap(AOTCodeHeap *heap) { heaps()->append(heap); }
+void AOTLoader::add_library(AOTLib *lib) { libraries()->append(lib); }
+#endif
+
+#endif // SHARE_AOT_AOTLOADER_INLINE_HPP
diff --git a/src/hotspot/share/aot/compiledIC_aot.cpp b/src/hotspot/share/aot/compiledIC_aot.cpp
new file mode 100644
index 000000000..dec97e5c2
--- /dev/null
+++ b/src/hotspot/share/aot/compiledIC_aot.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+
+#include "aot/compiledIC_aot.hpp"
+
+bool CompiledPltStaticCall::is_call_to_interpreted() const {
+ // It is a call to interpreted, if it calls to a stub. Hence, the destination
+ // must be in the stub part of the nmethod that contains the call
+ return destination() == _call->plt_c2i_stub();
+}
+
+address CompiledPltStaticCall::find_stub() {
+ // It is static NativePltCall. Return c2i stub address.
+ return _call->plt_c2i_stub();
+}
diff --git a/src/hotspot/share/aot/compiledIC_aot.hpp b/src/hotspot/share/aot/compiledIC_aot.hpp
new file mode 100644
index 000000000..664377c1c
--- /dev/null
+++ b/src/hotspot/share/aot/compiledIC_aot.hpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef SHARE_AOT_COMPILEDIC_AOT_HPP
+#define SHARE_AOT_COMPILEDIC_AOT_HPP
+
+#include "code/compiledIC.hpp"
+#include "code/nativeInst.hpp"
+#include "interpreter/linkResolver.hpp"
+#include "oops/compiledICHolder.hpp"
+
+class CompiledPltStaticCall: public CompiledStaticCall {
+ friend class CompiledIC;
+ friend class PltNativeCallWrapper;
+
+ // Also used by CompiledIC
+ void set_to_interpreted(const methodHandle& callee, address entry);
+
+ address instruction_address() const { return _call->instruction_address(); }
+ void set_destination_mt_safe(address dest) { _call->set_destination_mt_safe(dest); }
+
+ NativePltCall* _call;
+
+ CompiledPltStaticCall(NativePltCall* call) : _call(call) {}
+
+ public:
+
+ inline static CompiledPltStaticCall* before(address return_addr) {
+ CompiledPltStaticCall* st = new CompiledPltStaticCall(nativePltCall_before(return_addr));
+ st->verify();
+ return st;
+ }
+
+ static inline CompiledPltStaticCall* at(address native_call) {
+ CompiledPltStaticCall* st = new CompiledPltStaticCall(nativePltCall_at(native_call));
+ st->verify();
+ return st;
+ }
+
+ static inline CompiledPltStaticCall* at(Relocation* call_site) {
+ return at(call_site->addr());
+ }
+
+ // Delegation
+ address destination() const { return _call->destination(); }
+
+ virtual bool is_call_to_interpreted() const;
+
+ // Stub support
+ address find_stub();
+ static void set_stub_to_clean(static_stub_Relocation* static_stub);
+
+ // Misc.
+ void print() PRODUCT_RETURN;
+ void verify() PRODUCT_RETURN;
+
+ protected:
+ virtual address resolve_call_stub() const { return _call->plt_resolve_call(); }
+ virtual void set_to_far(const methodHandle& callee, address entry) { set_to_compiled(entry); }
+ virtual const char* name() const { return "CompiledPltStaticCall"; }
+};
+
+#endif // SHARE_AOT_COMPILEDIC_AOT_HPP
diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp
index be1e14ad8..359b8a051 100644
--- a/src/hotspot/share/asm/codeBuffer.hpp
+++ b/src/hotspot/share/asm/codeBuffer.hpp
@@ -406,6 +406,10 @@ class CodeBuffer: public StackObj {
address _last_insn; // used to merge consecutive memory barriers, loads or stores.
+#if INCLUDE_AOT
+ bool _immutable_PIC;
+#endif
+
#ifndef PRODUCT
CodeStrings _code_strings;
bool _collect_comments; // Indicate if we need to collect block comments at all.
@@ -422,6 +426,9 @@ class CodeBuffer: public StackObj {
_oop_recorder = NULL;
_overflow_arena = NULL;
_last_insn = NULL;
+#if INCLUDE_AOT
+ _immutable_PIC = false;
+#endif
#ifndef PRODUCT
_decode_begin = NULL;
@@ -668,6 +675,13 @@ class CodeBuffer: public StackObj {
// Log a little info about section usage in the CodeBuffer
void log_section_sizes(const char* name);
+#if INCLUDE_AOT
+ // True if this is a code buffer used for immutable PIC, i.e. AOT
+ // compilation.
+ bool immutable_PIC() { return _immutable_PIC; }
+ void set_immutable_PIC(bool pic) { _immutable_PIC = pic; }
+#endif
+
#ifndef PRODUCT
public:
// Printing / Decoding
diff --git a/src/hotspot/share/c1/c1_Compilation.hpp b/src/hotspot/share/c1/c1_Compilation.hpp
index dd0f8ed8c..aa9e33493 100644
--- a/src/hotspot/share/c1/c1_Compilation.hpp
+++ b/src/hotspot/share/c1/c1_Compilation.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -266,7 +266,7 @@ class Compilation: public StackObj {
// will compilation make optimistic assumptions that might lead to
// deoptimization and that the runtime will account for?
bool is_optimistic() {
- return CompilerConfig::is_c1_only_no_jvmci() && !is_profiling() &&
+ return CompilerConfig::is_c1_only_no_aot_or_jvmci() && !is_profiling() &&
(RangeCheckElimination || UseLoopInvariantCodeMotion) &&
method()->method_data()->trap_count(Deoptimization::Reason_none) == 0;
}
diff --git a/src/hotspot/share/c1/c1_LIRAssembler.cpp b/src/hotspot/share/c1/c1_LIRAssembler.cpp
index 989a6f8ad..7f5655dcb 100644
--- a/src/hotspot/share/c1/c1_LIRAssembler.cpp
+++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -483,7 +483,7 @@ void LIR_Assembler::emit_call(LIR_OpJavaCall* op) {
#if defined(IA32) && defined(COMPILER2)
// C2 leave fpu stack dirty clean it
- if (UseSSE < 2 && !CompilerConfig::is_c1_only_no_jvmci()) {
+ if (UseSSE < 2 && !CompilerConfig::is_c1_only_no_aot_or_jvmci()) {
int i;
for ( i = 1; i <= 7 ; i++ ) {
ffree(i);
diff --git a/src/hotspot/share/c1/c1_LIRAssembler.hpp b/src/hotspot/share/c1/c1_LIRAssembler.hpp
index c82baa15f..28cff1448 100644
--- a/src/hotspot/share/c1/c1_LIRAssembler.hpp
+++ b/src/hotspot/share/c1/c1_LIRAssembler.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -267,7 +267,11 @@ class LIR_Assembler: public CompilationResourceObj {
public:
static int call_stub_size() {
- return _call_stub_size;
+ if (UseAOT) {
+ return _call_stub_size + _call_aot_stub_size;
+ } else {
+ return _call_stub_size;
+ }
}
static int exception_handler_size() {
diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp
index 4c33bcf30..ce9d70b24 100644
--- a/src/hotspot/share/c1/c1_LIRGenerator.cpp
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -462,7 +462,7 @@ void LIRGenerator::klass2reg_with_patching(LIR_Opr r, ciMetadata* obj, CodeEmitI
/* C2 relies on constant pool entries being resolved (ciTypeFlow), so if tiered compilation
* is active and the class hasn't yet been resolved we need to emit a patch that resolves
* the class. */
- if ((!CompilerConfig::is_c1_only_no_jvmci() && need_resolve) || !obj->is_loaded() || PatchALot) {
+ if ((!CompilerConfig::is_c1_only_no_aot_or_jvmci() && need_resolve) || !obj->is_loaded() || PatchALot) {
assert(info != NULL, "info must be set if class is not loaded");
__ klass2reg_patch(NULL, r, info);
} else {
@@ -646,7 +646,7 @@ void LIRGenerator::monitor_exit(LIR_Opr object, LIR_Opr lock, LIR_Opr new_hdr, L
void LIRGenerator::print_if_not_loaded(const NewInstance* new_instance) {
if (PrintNotLoaded && !new_instance->klass()->is_loaded()) {
tty->print_cr(" ###class not loaded at new bci %d", new_instance->printable_bci());
- } else if (PrintNotLoaded && (!CompilerConfig::is_c1_only_no_jvmci() && new_instance->is_unresolved())) {
+ } else if (PrintNotLoaded && (!CompilerConfig::is_c1_only_no_aot_or_jvmci() && new_instance->is_unresolved())) {
tty->print_cr(" ###class not resolved at new bci %d", new_instance->printable_bci());
}
}
diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp
index 052d01336..3835a3f17 100644
--- a/src/hotspot/share/classfile/classFileParser.cpp
+++ b/src/hotspot/share/classfile/classFileParser.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -90,6 +90,9 @@
#if INCLUDE_JFR
#include "jfr/support/jfrTraceIdExtension.hpp"
#endif
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
// We generally try to create the oops directly when parsing, rather than
// allocating temporary data structures and copying the bytes twice. A
@@ -5237,6 +5240,26 @@ InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook,
assert(_klass == ik, "invariant");
+#if INCLUDE_AOT
+ if (ik->should_store_fingerprint()) {
+ ik->store_fingerprint(_stream->compute_fingerprint());
+ }
+
+ ik->set_has_passed_fingerprint_check(false);
+ if (UseAOT && ik->supers_have_passed_fingerprint_checks()) {
+ uint64_t aot_fp = AOTLoader::get_saved_fingerprint(ik);
+ uint64_t fp = ik->has_stored_fingerprint() ? ik->get_stored_fingerprint() : _stream->compute_fingerprint();
+ if (aot_fp != 0 && aot_fp == fp) {
+ // This class matches with a class saved in an AOT library
+ ik->set_has_passed_fingerprint_check(true);
+ } else {
+ ResourceMark rm;
+ log_info(class, fingerprint)("%s : expected = " PTR64_FORMAT " actual = " PTR64_FORMAT,
+ ik->external_name(), aot_fp, _stream->compute_fingerprint());
+ }
+ }
+#endif
+
return ik;
}
diff --git a/src/hotspot/share/classfile/classFileStream.cpp b/src/hotspot/share/classfile/classFileStream.cpp
index b65b827c5..a9ac5fcc2 100644
--- a/src/hotspot/share/classfile/classFileStream.cpp
+++ b/src/hotspot/share/classfile/classFileStream.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -75,3 +75,12 @@ const ClassFileStream* ClassFileStream::clone() const {
need_verify(),
from_boot_loader_modules_image());
}
+
+uint64_t ClassFileStream::compute_fingerprint() const {
+ int classfile_size = length();
+ int classfile_crc = ClassLoader::crc32(0, (const char*)buffer(), length());
+ uint64_t fingerprint = (uint64_t(classfile_size) << 32) | uint64_t(uint32_t(classfile_crc));
+ assert(fingerprint != 0, "must not be zero");
+
+ return fingerprint;
+}
diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp
index 7cdc25406..94cf3af68 100644
--- a/src/hotspot/share/classfile/systemDictionary.cpp
+++ b/src/hotspot/share/classfile/systemDictionary.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -89,6 +89,9 @@
#if INCLUDE_JBOOSTER
#include "jbooster/client/clientStartupSignal.hpp"
#endif // INCLUDE_JBOOSTER
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
ResolutionErrorTable* SystemDictionary::_resolution_errors = NULL;
SymbolPropertyTable* SystemDictionary::_invoke_method_table = NULL;
@@ -1215,6 +1218,23 @@ void SystemDictionary::load_shared_class_misc(InstanceKlass* ik, ClassLoaderData
// notify a class loaded from shared object
ClassLoadingService::notify_class_loaded(ik, true /* shared class */);
+
+#if INCLUDE_AOT
+ ik->set_has_passed_fingerprint_check(false);
+ if (UseAOT && ik->supers_have_passed_fingerprint_checks()) {
+ uint64_t aot_fp = AOTLoader::get_saved_fingerprint(ik);
+ uint64_t cds_fp = ik->get_stored_fingerprint();
+ if (aot_fp != 0 && aot_fp == cds_fp) {
+ // This class matches with a class saved in an AOT library
+ ik->set_has_passed_fingerprint_check(true);
+ } else {
+ if (log_is_enabled(Info, class, fingerprint)) {
+ ResourceMark rm;
+ log_info(class, fingerprint)("%s : expected = " PTR64_FORMAT " actual = " PTR64_FORMAT, ik->external_name(), aot_fp, cds_fp);
+ }
+ }
+ }
+#endif
}
#endif // INCLUDE_CDS
diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp
index 104e04fba..54258da76 100644
--- a/src/hotspot/share/code/codeBlob.hpp
+++ b/src/hotspot/share/code/codeBlob.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -46,7 +46,8 @@ struct CodeBlobType {
MethodProfiled = 1, // Execution level 2 and 3 (profiled) nmethods
NonNMethod = 2, // Non-nmethods like Buffers, Adapters and Runtime Stubs
All = 3, // All types (No code cache segmentation)
- NumTypes = 4 // Number of CodeBlobTypes
+ AOT = 4, // AOT methods
+ NumTypes = 5 // Number of CodeBlobTypes
};
};
@@ -55,6 +56,10 @@ struct CodeBlobType {
// Subtypes are:
// CompiledMethod : Compiled Java methods (include method that calls to native code)
// nmethod : JIT Compiled Java methods
+// AOTCompiledMethod : AOT Compiled Java methods - Not in the CodeCache!
+// AOTCompiledMethod objects are allocated in the C-Heap, the code they
+// point to is allocated in the AOTCodeHeap which is in the C-Heap as
+// well (i.e. it's the memory where the shared library was loaded to)
// RuntimeBlob : Non-compiled method code; generated glue code
// BufferBlob : Used for non-relocatable code such as interpreter, stubroutines, etc.
// AdapterBlob : Used to hold C2I/I2C adapters
@@ -69,12 +74,17 @@ struct CodeBlobType {
// UncommonTrapBlob : Used to handle uncommon traps
//
//
-// Layout : continuous in the CodeCache
+// Layout (all except AOTCompiledMethod) : continuous in the CodeCache
// - header
// - relocation
// - content space
// - instruction space
// - data space
+//
+// Layout (AOTCompiledMethod) : in the C-Heap
+// - header -\
+// ... |
+// - code <-/
class CodeBlobLayout;
@@ -140,6 +150,7 @@ public:
virtual bool is_adapter_blob() const { return false; }
virtual bool is_vtable_blob() const { return false; }
virtual bool is_method_handles_adapter_blob() const { return false; }
+ virtual bool is_aot() const { return false; }
virtual bool is_compiled() const { return false; }
virtual bool is_optimized_entry_blob() const { return false; }
@@ -242,6 +253,7 @@ public:
#ifndef PRODUCT
void set_strings(CodeStrings& strings) {
+ assert(!is_aot(), "invalid on aot");
_strings.copy(strings);
}
#endif
diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp
index 61f8c0f51..254ddbf5c 100644
--- a/src/hotspot/share/code/codeCache.cpp
+++ b/src/hotspot/share/code/codeCache.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -72,6 +72,9 @@
#include "opto/compile.hpp"
#include "opto/node.hpp"
#endif
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
// Helper class for printing in CodeCache
class CodeBlob_sizes {
@@ -698,6 +701,9 @@ void CodeCache::metadata_do(MetadataClosure* f) {
while(iter.next()) {
iter.method()->metadata_do(f);
}
+#if INCLUDE_AOT
+ AOTLoader::metadata_do(f);
+#endif
}
int CodeCache::alignment_unit() {
@@ -983,6 +989,13 @@ void codeCache_init() {
CodeCache::initialize();
}
+#if INCLUDE_AOT
+void AOTLoader_init() {
+ // Load AOT libraries and add AOT code heaps.
+ AOTLoader::initialize();
+}
+#endif
+
//------------------------------------------------------------------------------------------------
int CodeCache::number_of_nmethods_with_dependencies() {
@@ -1044,6 +1057,13 @@ CompiledMethod* CodeCache::find_compiled(void* start) {
return (CompiledMethod*)cb;
}
+#if INCLUDE_AOT
+bool CodeCache::is_far_target(address target) {
+ return NativeCall::is_far_call(_low_bound, target) ||
+ NativeCall::is_far_call(_high_bound, target);
+}
+#endif
+
#if INCLUDE_JVMTI
// RedefineClasses support for saving nmethods that are dependent on "old" methods.
// We don't really expect this table to grow very large. If it does, it can become a hashtable.
@@ -1093,6 +1113,13 @@ void CodeCache::old_nmethods_do(MetadataClosure* f) {
// Just marks the methods in this class as needing deoptimization
void CodeCache::mark_for_evol_deoptimization(InstanceKlass* dependee) {
assert(SafepointSynchronize::is_at_safepoint(), "Can only do this at a safepoint!");
+
+#if INCLUDE_AOT
+ // Mark dependent AOT nmethods, which are only found via the class redefined.
+ // TODO: add dependencies to aotCompiledMethod's metadata section so this isn't
+ // needed.
+ AOTLoader::mark_evol_dependent_methods(dependee);
+#endif
}
diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp
index 4825b63df..8ff8dc765 100644
--- a/src/hotspot/share/code/codeCache.hpp
+++ b/src/hotspot/share/code/codeCache.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -205,6 +205,11 @@ class CodeCache : AllStatic {
static address high_bound() { return _high_bound; }
static address high_bound(int code_blob_type);
+#if INCLUDE_AOT
+ // Have to use far call instructions to call this pc.
+ static bool is_far_target(address pc);
+#endif
+
// Profiling
static size_t capacity();
static size_t unallocated_capacity(int code_blob_type);
@@ -226,6 +231,7 @@ class CodeCache : AllStatic {
static bool code_blob_type_accepts_compiled(int type) {
bool result = type == CodeBlobType::All || type <= CodeBlobType::MethodProfiled;
+ AOT_ONLY( result = result || type == CodeBlobType::AOT; )
return result;
}
diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp
index 8ed42270c..396c40ce9 100644
--- a/src/hotspot/share/code/compiledIC.cpp
+++ b/src/hotspot/share/code/compiledIC.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -425,7 +425,7 @@ bool CompiledIC::set_to_monomorphic(CompiledICInfo& info) {
// transitions are mt_safe
Thread *thread = Thread::current();
- if (info.to_interpreter()) {
+ if (info.to_interpreter() || info.to_aot()) {
// Call to interpreter
if (info.is_optimized() && is_optimized()) {
assert(is_clean(), "unsafe IC path");
@@ -439,8 +439,9 @@ bool CompiledIC::set_to_monomorphic(CompiledICInfo& info) {
if (TraceICs) {
ResourceMark rm(thread);
- tty->print_cr ("IC@" INTPTR_FORMAT ": monomorphic to interpreter: %s",
+ tty->print_cr ("IC@" INTPTR_FORMAT ": monomorphic to %s: %s",
p2i(instruction_address()),
+ (info.to_aot() ? "aot" : "interpreter"),
method->print_value_string());
}
} else {
@@ -540,13 +541,19 @@ void CompiledIC::compute_monomorphic_entry(const methodHandle& method,
entry = method_code->entry_point();
}
}
- if (entry != NULL) {
- // Call to near compiled code.
+ bool far_c2a = entry != NULL && caller_is_nmethod && method_code->is_far_code();
+ if (entry != NULL && !far_c2a) {
+ // Call to near compiled code (nmethod or aot).
info.set_compiled_entry(entry, is_optimized ? NULL : receiver_klass, is_optimized);
} else {
if (is_optimized) {
- // Use stub entry
- info.set_interpreter_entry(method()->get_c2i_entry(), method());
+ if (far_c2a) {
+ // Call to aot code from nmethod.
+ info.set_aot_entry(entry, method());
+ } else {
+ // Use stub entry
+ info.set_interpreter_entry(method()->get_c2i_entry(), method());
+ }
} else {
// Use icholder entry
assert(method_code == NULL || method_code->is_compiled(), "must be compiled");
@@ -607,6 +614,13 @@ bool CompiledDirectStaticCall::is_call_to_interpreted() const {
return cm->stub_contains(destination());
}
+bool CompiledDirectStaticCall::is_call_to_far() const {
+ // It is a call to aot method, if it calls to a stub. Hence, the destination
+ // must be in the stub part of the nmethod that contains the call
+ CodeBlob* desc = CodeCache::find_blob(instruction_address());
+ return desc->as_compiled_method()->stub_contains(destination());
+}
+
void CompiledStaticCall::set_to_compiled(address entry) {
if (TraceICs) {
ResourceMark rm;
@@ -631,6 +645,11 @@ void CompiledStaticCall::set(const StaticCallInfo& info) {
if (info._to_interpreter) {
// Call to interpreted code
set_to_interpreted(info.callee(), info.entry());
+#if INCLUDE_AOT
+ } else if (info._to_aot) {
+ // Call to far code
+ set_to_far(info.callee(), info.entry());
+#endif
} else {
set_to_compiled(info.entry());
}
@@ -642,6 +661,12 @@ void CompiledStaticCall::compute_entry(const methodHandle& m, bool caller_is_nme
CompiledMethod* m_code = m->code();
info._callee = m;
if (m_code != NULL && m_code->is_in_use() && !m_code->is_unloading()) {
+ if (caller_is_nmethod && m_code->is_far_code()) {
+ // Call to far aot code from nmethod.
+ info._to_aot = true;
+ } else {
+ info._to_aot = false;
+ }
info._to_interpreter = false;
info._entry = m_code->verified_entry_point();
} else {
@@ -653,18 +678,18 @@ void CompiledStaticCall::compute_entry(const methodHandle& m, bool caller_is_nme
}
}
-address CompiledDirectStaticCall::find_stub_for(address instruction) {
+address CompiledDirectStaticCall::find_stub_for(address instruction, bool is_aot) {
// Find reloc. information containing this call-site
RelocIterator iter((nmethod*)NULL, instruction);
while (iter.next()) {
if (iter.addr() == instruction) {
switch(iter.type()) {
case relocInfo::static_call_type:
- return iter.static_call_reloc()->static_stub();
+ return iter.static_call_reloc()->static_stub(is_aot);
// We check here for opt_virtual_call_type, since we reuse the code
// from the CompiledIC implementation
case relocInfo::opt_virtual_call_type:
- return iter.opt_virtual_call_reloc()->static_stub();
+ return iter.opt_virtual_call_reloc()->static_stub(is_aot);
case relocInfo::poll_type:
case relocInfo::poll_return_type: // A safepoint can't overlap a call.
default:
@@ -675,8 +700,8 @@ address CompiledDirectStaticCall::find_stub_for(address instruction) {
return NULL;
}
-address CompiledDirectStaticCall::find_stub() {
- return CompiledDirectStaticCall::find_stub_for(instruction_address());
+address CompiledDirectStaticCall::find_stub(bool is_aot) {
+ return CompiledDirectStaticCall::find_stub_for(instruction_address(), is_aot);
}
address CompiledDirectStaticCall::resolve_call_stub() const {
@@ -709,6 +734,8 @@ void CompiledDirectStaticCall::print() {
tty->print("clean");
} else if (is_call_to_compiled()) {
tty->print("compiled");
+ } else if (is_call_to_far()) {
+ tty->print("far");
} else if (is_call_to_interpreted()) {
tty->print("interpreted");
}
diff --git a/src/hotspot/share/code/compiledIC.hpp b/src/hotspot/share/code/compiledIC.hpp
index ca4190abc..534cec05f 100644
--- a/src/hotspot/share/code/compiledIC.hpp
+++ b/src/hotspot/share/code/compiledIC.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -84,6 +84,7 @@ class CompiledICInfo : public StackObj {
bool _is_icholder; // Is the cached value a CompiledICHolder*
bool _is_optimized; // it is an optimized virtual call (i.e., can be statically bound)
bool _to_interpreter; // Call it to interpreter
+ bool _to_aot; // Call it to aot code
bool _release_icholder;
public:
address entry() const { return _entry; }
@@ -98,11 +99,13 @@ class CompiledICInfo : public StackObj {
}
bool is_optimized() const { return _is_optimized; }
bool to_interpreter() const { return _to_interpreter; }
+ bool to_aot() const { return _to_aot; }
void set_compiled_entry(address entry, Klass* klass, bool is_optimized) {
_entry = entry;
_cached_value = (void*)klass;
_to_interpreter = false;
+ _to_aot = false;
_is_icholder = false;
_is_optimized = is_optimized;
_release_icholder = false;
@@ -112,6 +115,17 @@ class CompiledICInfo : public StackObj {
_entry = entry;
_cached_value = (void*)method;
_to_interpreter = true;
+ _to_aot = false;
+ _is_icholder = false;
+ _is_optimized = true;
+ _release_icholder = false;
+ }
+
+ void set_aot_entry(address entry, Method* method) {
+ _entry = entry;
+ _cached_value = (void*)method;
+ _to_interpreter = false;
+ _to_aot = true;
_is_icholder = false;
_is_optimized = true;
_release_icholder = false;
@@ -121,13 +135,14 @@ class CompiledICInfo : public StackObj {
_entry = entry;
_cached_value = (void*)icholder;
_to_interpreter = true;
+ _to_aot = false;
_is_icholder = true;
_is_optimized = false;
_release_icholder = true;
}
CompiledICInfo(): _entry(NULL), _cached_value(NULL), _is_icholder(false),
- _is_optimized(false), _to_interpreter(false), _release_icholder(false) {
+ _is_optimized(false), _to_interpreter(false), _to_aot(false), _release_icholder(false) {
}
~CompiledICInfo() {
// In rare cases the info is computed but not used, so release any
@@ -326,6 +341,7 @@ class StaticCallInfo {
address _entry; // Entrypoint
methodHandle _callee; // Callee (used when calling interpreter)
bool _to_interpreter; // call to interpreted method (otherwise compiled)
+ bool _to_aot; // call to aot method (otherwise compiled)
friend class CompiledStaticCall;
friend class CompiledDirectStaticCall;
@@ -344,6 +360,9 @@ class CompiledStaticCall : public ResourceObj {
static int to_interp_stub_size();
static int to_trampoline_stub_size();
static int reloc_to_interp_stub();
+ static void emit_to_aot_stub(CodeBuffer &cbuf, address mark = NULL);
+ static int to_aot_stub_size();
+ static int reloc_to_aot_stub();
// Compute entry point given a method
static void compute_entry(const methodHandle& m, bool caller_is_nmethod, StaticCallInfo& info);
@@ -369,6 +388,9 @@ public:
protected:
virtual address resolve_call_stub() const = 0;
virtual void set_destination_mt_safe(address dest) = 0;
+#if INCLUDE_AOT
+ virtual void set_to_far(const methodHandle& callee, address entry) = 0;
+#endif
virtual void set_to_interpreted(const methodHandle& callee, address entry) = 0;
virtual const char* name() const = 0;
@@ -385,6 +407,9 @@ private:
void verify_mt_safe(const methodHandle& callee, address entry,
NativeMovConstReg* method_holder,
NativeJump* jump) PRODUCT_RETURN;
+#if INCLUDE_AOT
+ void set_to_far(const methodHandle& callee, address entry);
+#endif
address instruction_address() const { return _call->instruction_address(); }
void set_destination_mt_safe(address dest) { _call->set_destination_mt_safe(dest); }
@@ -414,10 +439,11 @@ private:
// State
virtual bool is_call_to_interpreted() const;
+ bool is_call_to_far() const;
// Stub support
- static address find_stub_for(address instruction);
- address find_stub();
+ static address find_stub_for(address instruction, bool is_aot);
+ address find_stub(bool is_aot);
static void set_stub_to_clean(static_stub_Relocation* static_stub);
// Misc.
diff --git a/src/hotspot/share/code/compiledMethod.cpp b/src/hotspot/share/code/compiledMethod.cpp
index 4e42b555d..bda6d74c6 100644
--- a/src/hotspot/share/code/compiledMethod.cpp
+++ b/src/hotspot/share/code/compiledMethod.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -72,6 +72,7 @@ CompiledMethod::CompiledMethod(Method* method, const char* name, CompilerType ty
void CompiledMethod::init_defaults() {
{ // avoid uninitialized fields, even for short time periods
+ _is_far_code = false;
_scopes_data_begin = NULL;
_deopt_handler_begin = NULL;
_deopt_mh_handler_begin = NULL;
diff --git a/src/hotspot/share/code/compiledMethod.hpp b/src/hotspot/share/code/compiledMethod.hpp
index 6c979f67a..737e4bc15 100644
--- a/src/hotspot/share/code/compiledMethod.hpp
+++ b/src/hotspot/share/code/compiledMethod.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -152,6 +152,9 @@ protected:
MarkForDeoptimizationStatus _mark_for_deoptimization_status; // Used for stack deoptimization
+ bool _is_far_code; // Code is far from CodeCache.
+ // Have to use far call instructions to call it from code in CodeCache.
+
// set during construction
unsigned int _has_unsafe_access:1; // May fault due to unsafe access.
unsigned int _has_method_handle_invokes:1; // Has this method MethodHandle invokes?
@@ -331,6 +334,8 @@ public:
const char* state() const;
+ bool is_far_code() const { return _is_far_code; }
+
bool inlinecache_check_contains(address addr) const {
return (addr >= code_begin() && addr < verified_entry_point());
}
diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp
index eef8e6b4b..f45270b01 100644
--- a/src/hotspot/share/code/nmethod.cpp
+++ b/src/hotspot/share/code/nmethod.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -441,6 +441,7 @@ void nmethod::init_defaults() {
_stack_traversal_mark = 0;
_load_reported = false; // jvmti state
_unload_reported = false;
+ _is_far_code = false; // nmethods are located in CodeCache
#ifdef ASSERT
_oops_are_stale = false;
@@ -2379,6 +2380,7 @@ nmethodLocker::nmethodLocker(address pc) {
// should pass zombie_ok == true.
void nmethodLocker::lock_nmethod(CompiledMethod* cm, bool zombie_ok) {
if (cm == NULL) return;
+ if (cm->is_aot()) return; // FIXME: Revisit once _lock_count is added to aot_method
nmethod* nm = cm->as_nmethod();
Atomic::inc(&nm->_lock_count);
assert(zombie_ok || !nm->is_zombie(), "cannot lock a zombie method: %p", nm);
@@ -2386,6 +2388,7 @@ void nmethodLocker::lock_nmethod(CompiledMethod* cm, bool zombie_ok) {
void nmethodLocker::unlock_nmethod(CompiledMethod* cm) {
if (cm == NULL) return;
+ if (cm->is_aot()) return; // FIXME: Revisit once _lock_count is added to aot_method
nmethod* nm = cm->as_nmethod();
Atomic::dec(&nm->_lock_count);
assert(nm->_lock_count >= 0, "unmatched nmethod lock/unlock");
@@ -2533,11 +2536,11 @@ void nmethod::verify_scopes() {
verify_interrupt_point(iter.addr());
break;
case relocInfo::opt_virtual_call_type:
- stub = iter.opt_virtual_call_reloc()->static_stub();
+ stub = iter.opt_virtual_call_reloc()->static_stub(false);
verify_interrupt_point(iter.addr());
break;
case relocInfo::static_call_type:
- stub = iter.static_call_reloc()->static_stub();
+ stub = iter.static_call_reloc()->static_stub(false);
//verify_interrupt_point(iter.addr());
break;
case relocInfo::runtime_call_type:
@@ -3480,11 +3483,28 @@ public:
}
virtual void set_destination_mt_safe(address dest) {
+#if INCLUDE_AOT
+ if (UseAOT) {
+ CodeBlob* callee = CodeCache::find_blob(dest);
+ CompiledMethod* cm = callee->as_compiled_method_or_null();
+ if (cm != NULL && cm->is_far_code()) {
+ // Temporary fix, see JDK-8143106
+ CompiledDirectStaticCall* csc = CompiledDirectStaticCall::at(instruction_address());
+ csc->set_to_far(methodHandle(Thread::current(), cm->method()), dest);
+ return;
+ }
+ }
+#endif
_call->set_destination_mt_safe(dest);
}
virtual void set_to_interpreted(const methodHandle& method, CompiledICInfo& info) {
CompiledDirectStaticCall* csc = CompiledDirectStaticCall::at(instruction_address());
+#if INCLUDE_AOT
+ if (info.to_aot()) {
+ csc->set_to_far(method, info.entry());
+ } else
+#endif
{
csc->set_to_interpreted(method, info.entry());
}
diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp
index 47769c53a..4e9e3177d 100644
--- a/src/hotspot/share/code/relocInfo.cpp
+++ b/src/hotspot/share/code/relocInfo.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -415,14 +415,18 @@ void static_stub_Relocation::pack_data_to(CodeSection* dest) {
short* p = (short*) dest->locs_end();
CodeSection* insts = dest->outer()->insts();
normalize_address(_static_call, insts);
- p = pack_1_int_to(p, scaled_offset(_static_call, insts->start()));
+ jint is_aot = _is_aot ? 1 : 0;
+ p = pack_2_ints_to(p, scaled_offset(_static_call, insts->start()), is_aot);
dest->set_locs_end((relocInfo*) p);
}
void static_stub_Relocation::unpack_data() {
address base = binding()->section_start(CodeBuffer::SECT_INSTS);
- jint offset = unpack_1_int();
+ jint offset;
+ jint is_aot;
+ unpack_2_ints(offset, is_aot);
_static_call = address_from_scaled_offset(offset, base);
+ _is_aot = (is_aot == 1);
}
void trampoline_stub_Relocation::pack_data_to(CodeSection* dest ) {
@@ -644,14 +648,14 @@ bool opt_virtual_call_Relocation::clear_inline_cache() {
return set_to_clean_no_ic_refill(icache);
}
-address opt_virtual_call_Relocation::static_stub() {
+address opt_virtual_call_Relocation::static_stub(bool is_aot) {
// search for the static stub who points back to this static call
address static_call_addr = addr();
RelocIterator iter(code());
while (iter.next()) {
if (iter.type() == relocInfo::static_stub_type) {
static_stub_Relocation* stub_reloc = iter.static_stub_reloc();
- if (stub_reloc->static_call() == static_call_addr) {
+ if (stub_reloc->static_call() == static_call_addr && stub_reloc->is_aot() == is_aot) {
return iter.addr();
}
}
@@ -685,14 +689,14 @@ bool static_call_Relocation::clear_inline_cache() {
}
-address static_call_Relocation::static_stub() {
+address static_call_Relocation::static_stub(bool is_aot) {
// search for the static stub who points back to this static call
address static_call_addr = addr();
RelocIterator iter(code());
while (iter.next()) {
if (iter.type() == relocInfo::static_stub_type) {
static_stub_Relocation* stub_reloc = iter.static_stub_reloc();
- if (stub_reloc->static_call() == static_call_addr) {
+ if (stub_reloc->static_call() == static_call_addr && stub_reloc->is_aot() == is_aot) {
return iter.addr();
}
}
diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp
index 57d2126fb..9a1f5327c 100644
--- a/src/hotspot/share/code/relocInfo.hpp
+++ b/src/hotspot/share/code/relocInfo.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1091,7 +1091,7 @@ class opt_virtual_call_Relocation : public CallRelocation {
bool clear_inline_cache();
// find the matching static_stub
- address static_stub();
+ address static_stub(bool is_aot);
};
@@ -1123,23 +1123,24 @@ class static_call_Relocation : public CallRelocation {
bool clear_inline_cache();
// find the matching static_stub
- address static_stub();
+ address static_stub(bool is_aot);
};
class static_stub_Relocation : public Relocation {
public:
- static RelocationHolder spec(address static_call) {
+ static RelocationHolder spec(address static_call, bool is_aot = false) {
RelocationHolder rh = newHolder();
- new(rh) static_stub_Relocation(static_call);
+ new(rh) static_stub_Relocation(static_call, is_aot);
return rh;
}
private:
address _static_call; // location of corresponding static_call
+ bool _is_aot; // trampoline to aot code
- static_stub_Relocation(address static_call)
+ static_stub_Relocation(address static_call, bool is_aot)
: Relocation(relocInfo::static_stub_type),
- _static_call(static_call) { }
+ _static_call(static_call), _is_aot(is_aot) { }
friend class RelocIterator;
static_stub_Relocation() : Relocation(relocInfo::static_stub_type) { }
@@ -1148,6 +1149,7 @@ class static_stub_Relocation : public Relocation {
bool clear_inline_cache();
address static_call() { return _static_call; }
+ bool is_aot() { return _is_aot; }
// data is packed as a scaled offset in "1_int" format: [c] or [Cc]
void pack_data_to(CodeSection* dest);
diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp
index 026915246..68297a5d0 100644
--- a/src/hotspot/share/compiler/compilationPolicy.cpp
+++ b/src/hotspot/share/compiler/compilationPolicy.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -235,6 +235,8 @@ public:
scale *= threshold_scaling;
}
switch(cur_level) {
+ case CompLevel_aot:
+ return b >= Tier3AOTBackEdgeThreshold * scale;
case CompLevel_none:
case CompLevel_limited_profile:
return b >= Tier3BackEdgeThreshold * scale;
@@ -248,6 +250,10 @@ public:
static bool apply(const methodHandle& method, CompLevel cur_level, int i, int b) {
double k = 1;
switch(cur_level) {
+ case CompLevel_aot: {
+ k = CompilationModeFlag::disable_intermediate() ? 1 : CompilationPolicy::threshold_scale(CompLevel_full_profile, Tier3LoadFeedback);
+ break;
+ }
case CompLevel_none:
// Fall through
case CompLevel_limited_profile: {
@@ -273,6 +279,9 @@ public:
scale *= threshold_scaling;
}
switch(cur_level) {
+ case CompLevel_aot:
+ return (i >= Tier3AOTInvocationThreshold * scale) ||
+ (i >= Tier3AOTMinInvocationThreshold * scale && i + b >= Tier3AOTCompileThreshold * scale);
case CompLevel_none:
case CompLevel_limited_profile:
return (i >= Tier3InvocationThreshold * scale) ||
@@ -288,6 +297,10 @@ public:
static bool apply(const methodHandle& method, CompLevel cur_level, int i, int b) {
double k = 1;
switch(cur_level) {
+ case CompLevel_aot: {
+ k = CompilationModeFlag::disable_intermediate() ? 1 : CompilationPolicy::threshold_scale(CompLevel_full_profile, Tier3LoadFeedback);
+ break;
+ }
case CompLevel_none:
case CompLevel_limited_profile: {
k = CompilationPolicy::threshold_scale(CompLevel_full_profile, Tier3LoadFeedback);
@@ -507,8 +520,8 @@ bool CompilationPolicy::verify_level(CompLevel level) {
return false;
}
- // Interpreter level is always valid.
- if (level == CompLevel_none) {
+ // AOT and interpreter levels are always valid.
+ if (level == CompLevel_aot || level == CompLevel_none) {
return true;
}
if (CompilationModeFlag::normal()) {
@@ -750,7 +763,7 @@ void CompilationPolicy::compile(const methodHandle& mh, int bci, CompLevel level
if (level == CompLevel_none) {
if (mh->has_compiled_code()) {
- // Happens when we switch to interpreter to profile.
+ // Happens when we switch from AOT to interpreter to profile.
MutexLocker ml(Compile_lock);
NoSafepointVerifier nsv;
if (mh->has_compiled_code()) {
@@ -764,6 +777,24 @@ void CompilationPolicy::compile(const methodHandle& mh, int bci, CompLevel level
}
return;
}
+ if (level == CompLevel_aot) {
+ if (mh->has_aot_code()) {
+ if (PrintTieredEvents) {
+ print_event(COMPILE, mh(), mh(), bci, level);
+ }
+ MutexLocker ml(Compile_lock);
+ NoSafepointVerifier nsv;
+ if (mh->has_aot_code() && mh->code() != mh->aot_code()) {
+ mh->aot_code()->make_entrant();
+ if (mh->has_compiled_code()) {
+ mh->code()->make_not_entrant();
+ }
+ MutexLocker pl(CompiledMethod_lock, Mutex::_no_safepoint_check_flag);
+ Method::set_code(mh, mh->aot_code());
+ }
+ }
+ return;
+ }
if (!CompilationModeFlag::disable_intermediate()) {
// Check if the method can be compiled. If it cannot be compiled with C1, continue profiling
@@ -1016,6 +1047,16 @@ CompLevel CompilationPolicy::common(const methodHandle& method, CompLevel cur_le
} else {
switch(cur_level) {
default: break;
+ case CompLevel_aot:
+ // If we were at full profile level, would we switch to full opt?
+ if (common<Predicate>(method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) {
+ next_level = CompLevel_full_optimization;
+ } else if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <=
+ Tier3DelayOff * compiler_count(CompLevel_full_optimization) &&
+ Predicate::apply(method, cur_level, i, b))) {
+ next_level = CompilationModeFlag::disable_intermediate() ? CompLevel_none : CompLevel_full_profile;
+ }
+ break;
case CompLevel_none:
// If we were at full profile level, would we switch to full opt?
if (common<Predicate>(method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) {
@@ -1120,6 +1161,26 @@ CompLevel CompilationPolicy::loop_event(const methodHandle& method, CompLevel cu
return next_level;
}
+bool CompilationPolicy::maybe_switch_to_aot(const methodHandle& mh, CompLevel cur_level, CompLevel next_level, TRAPS) {
+ if (UseAOT) {
+ if (cur_level == CompLevel_full_profile || cur_level == CompLevel_none) {
+ // If the current level is full profile or interpreter and we're switching to any other level,
+ // activate the AOT code back first so that we won't waste time overprofiling.
+ compile(mh, InvocationEntryBci, CompLevel_aot, THREAD);
+ // Fall through for JIT compilation.
+ }
+ if (next_level == CompLevel_limited_profile && cur_level != CompLevel_aot && mh->has_aot_code()) {
+ // If the next level is limited profile, use the aot code (if there is any),
+ // since it's essentially the same thing.
+ compile(mh, InvocationEntryBci, CompLevel_aot, THREAD);
+ // Not need to JIT, we're done.
+ return true;
+ }
+ }
+ return false;
+}
+
+
// Handle the invocation event.
void CompilationPolicy::method_invocation_event(const methodHandle& mh, const methodHandle& imh,
CompLevel level, CompiledMethod* nm, TRAPS) {
@@ -1128,6 +1189,10 @@ void CompilationPolicy::method_invocation_event(const methodHandle& mh, const me
}
CompLevel next_level = call_event(mh, level, THREAD);
if (next_level != level) {
+ if (maybe_switch_to_aot(mh, level, next_level, THREAD)) {
+ // No JITting necessary
+ return;
+ }
if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh)) {
compile(mh, InvocationEntryBci, next_level, THREAD);
}
@@ -1158,7 +1223,14 @@ void CompilationPolicy::method_back_branch_event(const methodHandle& mh, const m
// enough calls.
CompLevel cur_level, next_level;
if (mh() != imh()) { // If there is an enclosing method
- {
+ if (level == CompLevel_aot) {
+ // Recompile the enclosing method to prevent infinite OSRs. Stay at AOT level while it's compiling.
+ if (max_osr_level != CompLevel_none && !CompileBroker::compilation_is_in_queue(mh)) {
+ CompLevel enclosing_level = limit_level(CompLevel_full_profile);
+ compile(mh, InvocationEntryBci, enclosing_level, THREAD);
+ }
+ } else {
+ // Current loop event level is not AOT
guarantee(nm != NULL, "Should have nmethod here");
cur_level = comp_level(mh());
next_level = call_event(mh, cur_level, THREAD);
@@ -1190,7 +1262,7 @@ void CompilationPolicy::method_back_branch_event(const methodHandle& mh, const m
next_level = CompLevel_full_profile;
}
if (cur_level != next_level) {
- if (!CompileBroker::compilation_is_in_queue(mh)) {
+ if (!maybe_switch_to_aot(mh, cur_level, next_level, THREAD) && !CompileBroker::compilation_is_in_queue(mh)) {
compile(mh, InvocationEntryBci, next_level, THREAD);
}
}
@@ -1199,7 +1271,7 @@ void CompilationPolicy::method_back_branch_event(const methodHandle& mh, const m
cur_level = comp_level(mh());
next_level = call_event(mh, cur_level, THREAD);
if (next_level != cur_level) {
- if (!CompileBroker::compilation_is_in_queue(mh)) {
+ if (!maybe_switch_to_aot(mh, cur_level, next_level, THREAD) && !CompileBroker::compilation_is_in_queue(mh)) {
compile(mh, InvocationEntryBci, next_level, THREAD);
}
}
diff --git a/src/hotspot/share/compiler/compilationPolicy.hpp b/src/hotspot/share/compiler/compilationPolicy.hpp
index 75571674f..8e870da38 100644
--- a/src/hotspot/share/compiler/compilationPolicy.hpp
+++ b/src/hotspot/share/compiler/compilationPolicy.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -210,6 +210,8 @@ class CompilationPolicy : AllStatic {
// Is method profiled enough?
static bool is_method_profiled(const methodHandle& method);
+ static bool maybe_switch_to_aot(const methodHandle& mh, CompLevel cur_level, CompLevel next_level, TRAPS);
+
static void set_c1_count(int x) { _c1_count = x; }
static void set_c2_count(int x) { _c2_count = x; }
diff --git a/src/hotspot/share/compiler/compilerDefinitions.cpp b/src/hotspot/share/compiler/compilerDefinitions.cpp
index 2784d6a96..23b550192 100644
--- a/src/hotspot/share/compiler/compilerDefinitions.cpp
+++ b/src/hotspot/share/compiler/compilerDefinitions.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -174,6 +174,9 @@ void CompilerConfig::set_client_emulation_mode_flags() {
#if INCLUDE_JVMCI
FLAG_SET_ERGO(EnableJVMCI, false);
FLAG_SET_ERGO(UseJVMCICompiler, false);
+#endif
+#if INCLUDE_AOT
+ FLAG_SET_ERGO(UseAOT, false);
#endif
if (FLAG_IS_DEFAULT(NeverActAsServerClassMachine)) {
FLAG_SET_ERGO(NeverActAsServerClassMachine, true);
@@ -209,6 +212,7 @@ void CompilerConfig::set_client_emulation_mode_flags() {
bool CompilerConfig::is_compilation_mode_selected() {
return !FLAG_IS_DEFAULT(TieredCompilation) ||
!FLAG_IS_DEFAULT(TieredStopAtLevel) ||
+ !FLAG_IS_DEFAULT(UseAOT) ||
!FLAG_IS_DEFAULT(CompilationMode)
JVMCI_ONLY(|| !FLAG_IS_DEFAULT(EnableJVMCI)
|| !FLAG_IS_DEFAULT(UseJVMCICompiler));
@@ -278,6 +282,14 @@ void CompilerConfig::set_legacy_emulation_flags() {
FLAG_SET_ERGO(Tier4BackEdgeThreshold, osr_threshold);
FLAG_SET_ERGO(Tier0ProfilingStartPercentage, InterpreterProfilePercentage);
}
+#if INCLUDE_AOT
+ if (UseAOT) {
+ FLAG_SET_ERGO(Tier3AOTInvocationThreshold, threshold);
+ FLAG_SET_ERGO(Tier3AOTMinInvocationThreshold, threshold);
+ FLAG_SET_ERGO(Tier3AOTCompileThreshold, threshold);
+ FLAG_SET_ERGO(Tier3AOTBackEdgeThreshold, CompilerConfig::is_c1_only() ? osr_threshold : osr_profile_threshold);
+ }
+#endif
} else {
// Normal tiered mode, ignore legacy flags
}
@@ -325,6 +337,23 @@ void CompilerConfig::set_compilation_policy_flags() {
FLAG_SET_DEFAULT(Tier0ProfilingStartPercentage, 33);
}
+#if INCLUDE_AOT
+ if (UseAOT) {
+ if (FLAG_IS_DEFAULT(Tier3AOTInvocationThreshold)) {
+ FLAG_SET_DEFAULT(Tier3AOTInvocationThreshold, 200);
+ }
+ if (FLAG_IS_DEFAULT(Tier3AOTMinInvocationThreshold)) {
+ FLAG_SET_DEFAULT(Tier3AOTMinInvocationThreshold, 100);
+ }
+ if (FLAG_IS_DEFAULT(Tier3AOTCompileThreshold)) {
+ FLAG_SET_DEFAULT(Tier3AOTCompileThreshold, 2000);
+ }
+ if (FLAG_IS_DEFAULT(Tier3AOTBackEdgeThreshold)) {
+ FLAG_SET_DEFAULT(Tier3AOTBackEdgeThreshold, 2000);
+ }
+ }
+#endif
+
if (FLAG_IS_DEFAULT(Tier4InvocationThreshold)) {
FLAG_SET_DEFAULT(Tier4InvocationThreshold, 5000);
}
diff --git a/src/hotspot/share/compiler/compilerDefinitions.hpp b/src/hotspot/share/compiler/compilerDefinitions.hpp
index 1c8096918..1f8d3f1a6 100644
--- a/src/hotspot/share/compiler/compilerDefinitions.hpp
+++ b/src/hotspot/share/compiler/compilerDefinitions.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -55,6 +55,7 @@ enum MethodCompilation {
// Enumeration to distinguish tiers of compilation
enum CompLevel {
+ CompLevel_aot = -2,
CompLevel_any = -1, // Used for querying the state
CompLevel_all = -1, // Used for changing the state
CompLevel_none = 0, // Interpreter
@@ -137,16 +138,18 @@ public:
constexpr static bool has_c2() { return COMPILER2_PRESENT(true) NOT_COMPILER2(false); }
constexpr static bool has_jvmci() { return JVMCI_ONLY(true) NOT_JVMCI(false); }
constexpr static bool has_tiered() { return has_c1() && (has_c2() || has_jvmci()); }
+ constexpr static bool has_aot() { return AOT_ONLY(true) NOT_AOT(false); }
+ static bool is_aot() { return AOT_ONLY(has_aot() && UseAOT) NOT_AOT(false); }
static bool is_jvmci_compiler() { return JVMCI_ONLY(has_jvmci() && UseJVMCICompiler) NOT_JVMCI(false); }
static bool is_jvmci() { return JVMCI_ONLY(has_jvmci() && EnableJVMCI) NOT_JVMCI(false); }
static bool is_interpreter_only();
// is_*_only() functions describe situations in which the JVM is in one way or another
// forced to use a particular compiler or their combination. The constraint functions
- // deliberately ignore the fact that there may also be methods installed
+ // deliberately ignore the fact that there may also be AOT methods and methods installed
// through JVMCI (where the JVMCI compiler was invoked not through the broker). Be sure
- // to check for those (using is_jvmci()) in situations where it matters.
+ // to check for those (using is_jvmci() and is_aot()) in situations where it matters.
//
// Is the JVM in a configuration that permits only c1-compiled methods (level 1,2,3)?
@@ -160,13 +163,13 @@ public:
return false;
}
- static bool is_c1_or_interpreter_only_no_jvmci() {
+ static bool is_c1_or_interpreter_only_no_aot_or_jvmci() {
assert(is_jvmci_compiler() && is_jvmci() || !is_jvmci_compiler(), "JVMCI compiler implies enabled JVMCI");
- return !is_jvmci() && (is_interpreter_only() || is_c1_only());
+ return !is_aot() && !is_jvmci() && (is_interpreter_only() || is_c1_only());
}
- static bool is_c1_only_no_jvmci() {
- return is_c1_only() && !is_jvmci();
+ static bool is_c1_only_no_aot_or_jvmci() {
+ return is_c1_only() && !is_aot() && !is_jvmci();
}
// Is the JVM in a configuration that permits only c1-compiled methods at level 1?
diff --git a/src/hotspot/share/compiler/compiler_globals.hpp b/src/hotspot/share/compiler/compiler_globals.hpp
index 6ec87001a..19c80e82a 100644
--- a/src/hotspot/share/compiler/compiler_globals.hpp
+++ b/src/hotspot/share/compiler/compiler_globals.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -190,6 +190,33 @@
"Back edge threshold at which tier 3 OSR compilation is invoked") \
range(0, max_jint) \
\
+ product(intx, Tier3AOTInvocationThreshold, 10000, \
+ "Compile if number of method invocations crosses this " \
+ "threshold if coming from AOT;" \
+ "with CompilationMode=high-only|high-only-quick-internal)" \
+ "determines when to transition from AOT to interpreter") \
+ range(0, max_jint) \
+ \
+ product(intx, Tier3AOTMinInvocationThreshold, 1000, \
+ "Minimum invocation to compile at tier 3 if coming from AOT;" \
+ "with CompilationMode=high-only|high-only-quick-internal)" \
+ "determines when to transition from AOT to interpreter") \
+ range(0, max_jint) \
+ \
+ product(intx, Tier3AOTCompileThreshold, 15000, \
+ "Threshold at which tier 3 compilation is invoked (invocation " \
+ "minimum must be satisfied) if coming from AOT;" \
+ "with CompilationMode=high-only|high-only-quick-internal)" \
+ "determines when to transition from AOT to interpreter") \
+ range(0, max_jint) \
+ \
+ product(intx, Tier3AOTBackEdgeThreshold, 120000, \
+ "Back edge threshold at which tier 3 OSR compilation is invoked " \
+ "if coming from AOT;" \
+ "with CompilationMode=high-only|high-only-quick-internal)" \
+ "determines when to transition from AOT to interpreter") \
+ range(0, max_jint) \
+ \
product(intx, Tier4InvocationThreshold, 5000, \
"Compile if number of method invocations crosses this " \
"threshold") \
diff --git a/src/hotspot/share/compiler/disassembler.cpp b/src/hotspot/share/compiler/disassembler.cpp
index 4cc2f8781..d41d159fd 100644
--- a/src/hotspot/share/compiler/disassembler.cpp
+++ b/src/hotspot/share/compiler/disassembler.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -893,9 +893,23 @@ void Disassembler::decode(CodeBlob* cb, outputStream* st) {
decode_env env(cb, st);
env.output()->print_cr("--------------------------------------------------------------------------------");
- env.output()->print("Decoding CodeBlob");
- if (cb->name() != NULL) {
- env.output()->print(", name: %s,", cb->name());
+ if (cb->is_aot()) {
+ env.output()->print("A ");
+ if (cb->is_compiled()) {
+ CompiledMethod* cm = (CompiledMethod*)cb;
+ env.output()->print("%d ",cm->compile_id());
+ cm->method()->method_holder()->name()->print_symbol_on(env.output());
+ env.output()->print(".");
+ cm->method()->name()->print_symbol_on(env.output());
+ cm->method()->signature()->print_symbol_on(env.output());
+ } else {
+ env.output()->print_cr("%s", cb->name());
+ }
+ } else {
+ env.output()->print("Decoding CodeBlob");
+ if (cb->name() != NULL) {
+ env.output()->print(", name: %s,", cb->name());
+ }
}
env.output()->print_cr(" at [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(cb->code_begin()), p2i(cb->code_end()), ((jlong)(cb->code_end() - cb->code_begin())));
diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp
index f6fd08bdc..52c004f45 100644
--- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp
+++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -56,6 +56,7 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) :
// Root scanning phases
_gc_par_phases[ThreadRoots] = new WorkerDataArray<double>("ThreadRoots", "Thread Roots (ms):", max_gc_threads);
_gc_par_phases[CLDGRoots] = new WorkerDataArray<double>("CLDGRoots", "CLDG Roots (ms):", max_gc_threads);
+ AOT_ONLY(_gc_par_phases[AOTCodeRoots] = new WorkerDataArray<double>("AOTCodeRoots", "AOT Root Scan (ms):", max_gc_threads);)
_gc_par_phases[CMRefRoots] = new WorkerDataArray<double>("CMRefRoots", "CM RefProcessor Roots (ms):", max_gc_threads);
for (auto id : EnumRange<OopStorageSet::StrongId>()) {
diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp
index f374399df..395ff0593 100644
--- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp
+++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -50,6 +50,7 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
ExtRootScan,
ThreadRoots,
CLDGRoots,
+ AOT_ONLY(AOTCodeRoots COMMA)
CMRefRoots,
// For every strong OopStorage there will be one element in this enum,
// starting with StrongOopStorageSetRoots.
diff --git a/src/hotspot/share/gc/g1/g1RootProcessor.cpp b/src/hotspot/share/gc/g1/g1RootProcessor.cpp
index c8609718c..bad78b562 100644
--- a/src/hotspot/share/gc/g1/g1RootProcessor.cpp
+++ b/src/hotspot/share/gc/g1/g1RootProcessor.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,9 @@
#include "runtime/mutex.hpp"
#include "utilities/enumIterator.hpp"
#include "utilities/macros.hpp"
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
G1RootProcessor::G1RootProcessor(G1CollectedHeap* g1h, uint n_workers) :
_g1h(g1h),
@@ -198,6 +201,15 @@ void G1RootProcessor::process_vm_roots(G1RootClosures* closures,
uint worker_id) {
OopClosure* strong_roots = closures->strong_oops();
+#if INCLUDE_AOT
+ if (_process_strong_tasks.try_claim_task(G1RP_PS_aot_oops_do)) {
+ if (UseAOT) {
+ G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::AOTCodeRoots, worker_id);
+ AOTLoader::oops_do(strong_roots);
+ }
+ }
+#endif
+
for (auto id : EnumRange<OopStorageSet::StrongId>()) {
G1GCPhaseTimes::GCParPhases phase = G1GCPhaseTimes::strong_oopstorage_phase(id);
G1GCParPhaseTimesTracker x(phase_times, phase, worker_id);
diff --git a/src/hotspot/share/gc/g1/g1RootProcessor.hpp b/src/hotspot/share/gc/g1/g1RootProcessor.hpp
index cdb843e57..403c36c5f 100644
--- a/src/hotspot/share/gc/g1/g1RootProcessor.hpp
+++ b/src/hotspot/share/gc/g1/g1RootProcessor.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -55,6 +55,7 @@ class G1RootProcessor : public StackObj {
enum G1H_process_roots_tasks {
G1RP_PS_ClassLoaderDataGraph_oops_do,
G1RP_PS_CodeCache_oops_do,
+ AOT_ONLY(G1RP_PS_aot_oops_do COMMA)
G1RP_PS_refProcessor_oops_do,
// Leave this one last.
G1RP_PS_NumElements
diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp
index e588cae89..f5e64b844 100644
--- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp
+++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -89,6 +89,9 @@
#if INCLUDE_JVMCI
#include "jvmci/jvmci.hpp"
#endif
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
#include <math.h>
@@ -1987,6 +1990,9 @@ static void mark_from_roots_work(ParallelRootType::Value root_type, uint worker_
case ParallelRootType::code_cache:
// Do not treat nmethods as strong roots for mark/sweep, since we can unload them.
//ScavengableNMethods::scavengable_nmethods_do(CodeBlobToOopClosure(&mark_and_push_closure));
+#if INCLUDE_AOT
+ AOTLoader::oops_do(&mark_and_push_closure);
+#endif
break;
case ParallelRootType::sentinel:
@@ -2165,6 +2171,9 @@ class PSAdjustTask final : public AbstractGangTask {
enum PSAdjustSubTask {
PSAdjustSubTask_code_cache,
+#if INCLUDE_AOT
+ PSAdjustSubTask_aot,
+#endif
PSAdjustSubTask_old_ref_process,
PSAdjustSubTask_young_ref_process,
@@ -2208,6 +2217,11 @@ public:
CodeBlobToOopClosure adjust_code(&adjust, CodeBlobToOopClosure::FixRelocations);
CodeCache::blobs_do(&adjust_code);
}
+#if INCLUDE_AOT
+ if (_sub_tasks.try_claim_task(PSAdjustSubTask_aot)) {
+ AOTLoader::oops_do(&adjust);
+ }
+#endif
if (_sub_tasks.try_claim_task(PSAdjustSubTask_old_ref_process)) {
PSParallelCompact::ref_processor()->weak_oops_do(&adjust);
}
diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp
index c4011fff4..98ec438ad 100644
--- a/src/hotspot/share/gc/parallel/psScavenge.cpp
+++ b/src/hotspot/share/gc/parallel/psScavenge.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -69,6 +69,9 @@
#include "runtime/vmOperations.hpp"
#include "services/memoryService.hpp"
#include "utilities/stack.inline.hpp"
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
HeapWord* PSScavenge::_to_space_top_before_gc = NULL;
int PSScavenge::_consecutive_skipped_scavenges = 0;
@@ -102,6 +105,9 @@ static void scavenge_roots_work(ParallelRootType::Value root_type, uint worker_i
{
MarkingCodeBlobClosure code_closure(&roots_to_old_closure, CodeBlobToOopClosure::FixRelocations);
ScavengableNMethods::nmethods_do(&code_closure);
+#if INCLUDE_AOT
+ AOTLoader::oops_do(&roots_closure);
+#endif
}
break;
diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.cpp b/src/hotspot/share/gc/shared/genCollectedHeap.cpp
index 12a835554..ab050aa06 100644
--- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp
+++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -78,6 +78,9 @@
#if INCLUDE_JVMCI
#include "jvmci/jvmci.hpp"
#endif
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
GenCollectedHeap::GenCollectedHeap(Generation::Name young,
Generation::Name old,
@@ -789,6 +792,12 @@ void GenCollectedHeap::process_roots(ScanningOption so,
Threads::oops_do(strong_roots, roots_from_code_p);
+#if INCLUDE_AOT
+ if (UseAOT) {
+ AOTLoader::oops_do(strong_roots);
+ }
+#endif
+
OopStorageSet::strong_oops_do(strong_roots);
if (so & SO_ScavengeCodeCache) {
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp
index 7d31ff02e..e861ef569 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2022, Red Hat, Inc. All rights reserved.
+ * Copyright (c) 2018, 2023, Red Hat, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -159,6 +159,14 @@ void ShenandoahArguments::initialize() {
FLAG_SET_DEFAULT(ClassUnloadingWithConcurrentMark, false);
}
+ // AOT is not supported yet
+ if (UseAOT) {
+ if (!FLAG_IS_DEFAULT(UseAOT)) {
+ warning("Shenandoah does not support AOT at this moment, disabling UseAOT");
+ }
+ FLAG_SET_DEFAULT(UseAOT, false);
+ }
+
// TLAB sizing policy makes resizing decisions before each GC cycle. It averages
// historical data, assigning more recent data the weight according to TLABAllocationWeight.
// Current default is good for generational collectors that run frequent young GCs.
diff --git a/src/hotspot/share/jfr/leakprofiler/chains/rootSetClosure.cpp b/src/hotspot/share/jfr/leakprofiler/chains/rootSetClosure.cpp
index 9a76d3b40..15199a86b 100644
--- a/src/hotspot/share/jfr/leakprofiler/chains/rootSetClosure.cpp
+++ b/src/hotspot/share/jfr/leakprofiler/chains/rootSetClosure.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,9 @@
#include "runtime/thread.hpp"
#include "services/management.hpp"
#include "utilities/align.hpp"
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
template <typename Delegate>
RootSetClosure<Delegate>::RootSetClosure(Delegate* delegate) : _delegate(delegate) {}
@@ -71,6 +74,9 @@ void RootSetClosure<Delegate>::process() {
// We don't follow code blob oops, because they have misaligned oops.
Threads::oops_do(this, NULL);
OopStorageSet::strong_oops_do(this);
+#if INCLUDE_AOT
+ AOTLoader::oops_do(this);
+#endif
}
template class RootSetClosure<BFSClosure>;
diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp
index d66e9236d..5b779b4b4 100644
--- a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -44,6 +44,9 @@
#include "services/management.hpp"
#include "utilities/enumIterator.hpp"
#include "utilities/growableArray.hpp"
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
class ReferenceLocateClosure : public OopClosure {
protected:
@@ -100,6 +103,9 @@ class ReferenceToRootClosure : public StackObj {
bool do_cldg_roots();
bool do_oop_storage_roots();
bool do_string_table_roots();
+#if INCLUDE_AOT
+ bool do_aot_loader_roots();
+#endif
bool do_roots();
@@ -148,6 +154,15 @@ bool ReferenceToRootClosure::do_oop_storage_roots() {
return false;
}
+#if INCLUDE_AOT
+bool ReferenceToRootClosure::do_aot_loader_roots() {
+ assert(!complete(), "invariant");
+ ReferenceLocateClosure rcl(_callback, OldObjectRoot::_aot, OldObjectRoot::_type_undetermined, NULL);
+ AOTLoader::oops_do(&rcl);
+ return rcl.complete();
+}
+#endif
+
bool ReferenceToRootClosure::do_roots() {
assert(!complete(), "invariant");
assert(OldObjectRoot::_system_undetermined == _info._system, "invariant");
@@ -163,6 +178,13 @@ bool ReferenceToRootClosure::do_roots() {
return true;
}
+#if INCLUDE_AOT
+ if (do_aot_loader_roots()) {
+ _complete = true;
+ return true;
+ }
+#endif
+
return false;
}
diff --git a/src/hotspot/share/jfr/leakprofiler/utilities/rootType.cpp b/src/hotspot/share/jfr/leakprofiler/utilities/rootType.cpp
index aefbc59a5..6827d3856 100644
--- a/src/hotspot/share/jfr/leakprofiler/utilities/rootType.cpp
+++ b/src/hotspot/share/jfr/leakprofiler/utilities/rootType.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -57,6 +57,8 @@ const char* OldObjectRoot::system_description(System system) {
return "Class Loader Data";
case _code_cache:
return "Code Cache";
+ case _aot:
+ return "AOT";
#if INCLUDE_JVMCI
case _jvmci:
return "JVMCI";
diff --git a/src/hotspot/share/jfr/leakprofiler/utilities/rootType.hpp b/src/hotspot/share/jfr/leakprofiler/utilities/rootType.hpp
index ffc47c7b8..bcd7f5b6c 100644
--- a/src/hotspot/share/jfr/leakprofiler/utilities/rootType.hpp
+++ b/src/hotspot/share/jfr/leakprofiler/utilities/rootType.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,7 @@ class OldObjectRoot : public AllStatic {
_strong_oop_storage_set_last = _strong_oop_storage_set_first + EnumRange<OopStorageSet::StrongId>().size() - 1,
_class_loader_data,
_code_cache,
+ _aot,
JVMCI_ONLY(_jvmci COMMA)
_number_of_systems
};
diff --git a/src/hotspot/share/jvmci/compilerRuntime.cpp b/src/hotspot/share/jvmci/compilerRuntime.cpp
new file mode 100644
index 000000000..cf48aa862
--- /dev/null
+++ b/src/hotspot/share/jvmci/compilerRuntime.cpp
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "classfile/vmSymbols.hpp"
+#include "compiler/compilationPolicy.hpp"
+#include "interpreter/linkResolver.hpp"
+#include "jvmci/compilerRuntime.hpp"
+#include "oops/cpCache.inline.hpp"
+#include "oops/klass.inline.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/deoptimization.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
+#include "runtime/vframe.inline.hpp"
+#include "utilities/sizes.hpp"
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
+
+// Resolve and allocate String
+JRT_BLOCK_ENTRY(void, CompilerRuntime::resolve_string_by_symbol(JavaThread* current, void* string_result, const char* name))
+ JRT_BLOCK
+ oop str = *(oop*)string_result; // Is it resolved already?
+ if (str == NULL) { // Do resolution
+ // First 2 bytes of name contains length (number of bytes).
+ int len = Bytes::get_Java_u2((address)name);
+ name += 2;
+ TempNewSymbol sym = SymbolTable::new_symbol(name, len);
+ str = StringTable::intern(sym, CHECK);
+ assert(java_lang_String::is_instance(str), "must be string");
+ *(oop*)string_result = str; // Store result
+ }
+ assert(str != NULL, "Should be allocated!");
+ current->set_vm_result(str);
+ JRT_BLOCK_END
+JRT_END
+
+
+
+Klass* CompilerRuntime::resolve_klass_helper(const char* name, int len, TRAPS) {
+ JavaThread* current = THREAD->as_Java_thread();
+ ResourceMark rm(current);
+ // last java frame on stack (which includes native call frames)
+ RegisterMap cbl_map(current, false);
+ // Skip stub
+ frame caller_frame = current->last_frame().sender(&cbl_map);
+ CodeBlob* caller_cb = caller_frame.cb();
+ guarantee(caller_cb != NULL && caller_cb->is_compiled(), "must be called from compiled method");
+ CompiledMethod* caller_nm = caller_cb->as_compiled_method_or_null();
+ methodHandle caller(current, caller_nm->method());
+
+ // Use class loader of aot method.
+ Handle loader(current, caller->method_holder()->class_loader());
+ Handle protection_domain(current, caller->method_holder()->protection_domain());
+
+ TempNewSymbol sym = SymbolTable::new_symbol(name, len);
+ if (sym != NULL && Signature::has_envelope(sym)) {
+ // Ignore wrapping L and ;
+ sym = Signature::strip_envelope(sym);
+ }
+ if (sym == NULL) {
+ return NULL;
+ }
+ Klass* k = SystemDictionary::resolve_or_fail(sym, loader, protection_domain, true, CHECK_NULL);
+
+ return k;
+}
+
+// Resolve Klass
+JRT_BLOCK_ENTRY(Klass*, CompilerRuntime::resolve_klass_by_symbol(JavaThread* current, Klass** klass_result, const char* name))
+ Klass* k = NULL;
+ JRT_BLOCK
+ k = *klass_result; // Is it resolved already?
+ if (k == NULL) { // Do resolution
+ // First 2 bytes of name contains length (number of bytes).
+ int len = Bytes::get_Java_u2((address)name);
+ name += 2;
+ k = CompilerRuntime::resolve_klass_helper(name, len, CHECK_NULL);
+ *klass_result = k; // Store result
+ }
+ JRT_BLOCK_END
+ assert(k != NULL, " Should be loaded!");
+ return k;
+JRT_END
+
+
+Method* CompilerRuntime::resolve_method_helper(Klass* klass, const char* method_name, int method_name_len,
+ const char* signature_name, int signature_name_len) {
+ Method* m = NULL;
+ TempNewSymbol name_symbol = SymbolTable::probe(method_name, method_name_len);
+ TempNewSymbol signature_symbol = SymbolTable::probe(signature_name, signature_name_len);
+ if (name_symbol != NULL && signature_symbol != NULL) {
+ if (name_symbol == vmSymbols::object_initializer_name() ||
+ name_symbol == vmSymbols::class_initializer_name()) {
+ // Never search superclasses for constructors
+ if (klass->is_instance_klass()) {
+ m = InstanceKlass::cast(klass)->find_method(name_symbol, signature_symbol);
+ }
+ } else {
+ m = klass->lookup_method(name_symbol, signature_symbol);
+ if (m == NULL && klass->is_instance_klass()) {
+ m = InstanceKlass::cast(klass)->lookup_method_in_ordered_interfaces(name_symbol, signature_symbol);
+ }
+ }
+ }
+ return m;
+}
+
+JRT_BLOCK_ENTRY(void, CompilerRuntime::resolve_dynamic_invoke(JavaThread* current, oop* appendix_result))
+ JRT_BLOCK
+ {
+ ResourceMark rm(current);
+ vframeStream vfst(current, true); // Do not skip and javaCalls
+ assert(!vfst.at_end(), "Java frame must exist");
+ methodHandle caller(current, vfst.method());
+ InstanceKlass* holder = caller->method_holder();
+ int bci = vfst.bci();
+ Bytecode_invoke bytecode(caller, bci);
+ int index = bytecode.index();
+
+ // Make sure it's resolved first
+ CallInfo callInfo;
+ constantPoolHandle cp(current, holder->constants());
+ ConstantPoolCacheEntry* cp_cache_entry = cp->cache()->entry_at(cp->decode_cpcache_index(index, true));
+ Bytecodes::Code invoke_code = bytecode.invoke_code();
+ if (!cp_cache_entry->is_resolved(invoke_code)) {
+ LinkResolver::resolve_invoke(callInfo, Handle(), cp, index, invoke_code, CHECK);
+ if (bytecode.is_invokedynamic()) {
+ cp_cache_entry->set_dynamic_call(cp, callInfo);
+ } else {
+ cp_cache_entry->set_method_handle(cp, callInfo);
+ }
+ vmassert(cp_cache_entry->is_resolved(invoke_code), "sanity");
+ }
+
+ Handle appendix(current, cp_cache_entry->appendix_if_resolved(cp));
+ Klass *appendix_klass = appendix.is_null() ? NULL : appendix->klass();
+
+ methodHandle adapter_method(current, cp_cache_entry->f1_as_method());
+ InstanceKlass *adapter_klass = adapter_method->method_holder();
+
+ if (appendix_klass != NULL && appendix_klass->is_instance_klass()) {
+ vmassert(InstanceKlass::cast(appendix_klass)->is_initialized(), "sanity");
+ }
+ if (!adapter_klass->is_initialized()) {
+ // Force initialization of adapter class
+ adapter_klass->initialize(CHECK);
+ // Double-check that it was really initialized,
+ // because we could be doing a recursive call
+ // from inside <clinit>.
+ }
+
+ int cpi = cp_cache_entry->constant_pool_index();
+ if (!AOTLoader::reconcile_dynamic_invoke(holder, cpi, adapter_method(),
+ appendix_klass)) {
+ return;
+ }
+
+ *appendix_result = appendix();
+ current->set_vm_result(appendix());
+ }
+ JRT_BLOCK_END
+JRT_END
+
+JRT_BLOCK_ENTRY(MethodCounters*, CompilerRuntime::resolve_method_by_symbol_and_load_counters(JavaThread* current, MethodCounters** counters_result, Klass* klass, const char* data))
+ MethodCounters* c = *counters_result; // Is it resolved already?
+ JRT_BLOCK
+ if (c == NULL) { // Do resolution
+ // Get method name and its length
+ int method_name_len = Bytes::get_Java_u2((address)data);
+ data += sizeof(u2);
+ const char* method_name = data;
+ data += method_name_len;
+
+ // Get signature and its length
+ int signature_name_len = Bytes::get_Java_u2((address)data);
+ data += sizeof(u2);
+ const char* signature_name = data;
+
+ assert(klass != NULL, "Klass parameter must not be null");
+ Method* m = resolve_method_helper(klass, method_name, method_name_len, signature_name, signature_name_len);
+ assert(m != NULL, "Method must resolve successfully");
+
+ // Create method counters immediately to avoid check at runtime.
+ c = m->get_method_counters(current);
+ if (c == NULL) {
+ THROW_MSG_NULL(vmSymbols::java_lang_OutOfMemoryError(), "Cannot allocate method counters");
+ }
+
+ *counters_result = c;
+ }
+ JRT_BLOCK_END
+ return c;
+JRT_END
+
+// Resolve and initialize Klass
+JRT_BLOCK_ENTRY(Klass*, CompilerRuntime::initialize_klass_by_symbol(JavaThread* current, Klass** klass_result, const char* name))
+ Klass* k = NULL;
+ JRT_BLOCK
+ k = klass_result[0]; // Is it initialized already?
+ if (k == NULL) { // Do initialized
+ k = klass_result[1]; // Is it resolved already?
+ if (k == NULL) { // Do resolution
+ // First 2 bytes of name contains length (number of bytes).
+ int len = Bytes::get_Java_u2((address)name);
+ const char *cname = name + 2;
+ k = CompilerRuntime::resolve_klass_helper(cname, len, CHECK_NULL);
+ klass_result[1] = k; // Store resolved result
+ }
+ Klass* k0 = klass_result[0]; // Is it initialized already?
+ if (k0 == NULL && k != NULL && k->is_instance_klass()) {
+ // Force initialization of instance class
+ InstanceKlass::cast(k)->initialize(CHECK_NULL);
+ // Double-check that it was really initialized,
+ // because we could be doing a recursive call
+ // from inside <clinit>.
+ if (InstanceKlass::cast(k)->is_initialized()) {
+ klass_result[0] = k; // Store initialized result
+ }
+ }
+ }
+ JRT_BLOCK_END
+ assert(k != NULL, " Should be loaded!");
+ return k;
+JRT_END
+
+
+JRT_BLOCK_ENTRY(void, CompilerRuntime::invocation_event(JavaThread* current, MethodCounters* counters))
+ JRT_BLOCK
+ methodHandle mh(current, counters->method());
+ RegisterMap map(current, false);
+ // Compute the enclosing method
+ frame fr = current->last_frame().sender(&map);
+ CompiledMethod* cm = fr.cb()->as_compiled_method_or_null();
+ assert(cm != NULL && cm->is_compiled(), "Sanity check");
+ methodHandle emh(current, cm->method());
+ CompilationPolicy::event(emh, mh, InvocationEntryBci, InvocationEntryBci, CompLevel_aot, cm, CHECK);
+ JRT_BLOCK_END
+JRT_END
+
+JRT_BLOCK_ENTRY(void, CompilerRuntime::backedge_event(JavaThread* current, MethodCounters* counters, int branch_bci, int target_bci))
+ assert(branch_bci != InvocationEntryBci && target_bci != InvocationEntryBci, "Wrong bci");
+ assert(target_bci <= branch_bci, "Expected a back edge");
+ JRT_BLOCK
+ methodHandle mh(current, counters->method());
+ RegisterMap map(current, false);
+
+ // Compute the enclosing method
+ frame fr = current->last_frame().sender(&map);
+ CompiledMethod* cm = fr.cb()->as_compiled_method_or_null();
+ assert(cm != NULL && cm->is_compiled(), "Sanity check");
+ methodHandle emh(current, cm->method());
+ nmethod* osr_nm = CompilationPolicy::event(emh, mh, branch_bci, target_bci, CompLevel_aot, cm, CHECK);
+ if (osr_nm != NULL) {
+ Deoptimization::deoptimize_frame(current, fr.id());
+ }
+ JRT_BLOCK_END
+JRT_END
diff --git a/src/hotspot/share/jvmci/compilerRuntime.hpp b/src/hotspot/share/jvmci/compilerRuntime.hpp
new file mode 100644
index 000000000..98c2a5583
--- /dev/null
+++ b/src/hotspot/share/jvmci/compilerRuntime.hpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef SHARE_JVMCI_COMPILERRUNTIME_HPP
+#define SHARE_JVMCI_COMPILERRUNTIME_HPP
+
+#include "memory/allocation.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/klass.hpp"
+#include "oops/method.hpp"
+#include "utilities/exceptions.hpp"
+
+class CompilerRuntime : AllStatic {
+ public:
+ // Resolves klass for aot compiled method.
+ static Klass* resolve_klass_helper(const char* name, int len, TRAPS);
+ // Resolves method for aot compiled method.
+ static Method* resolve_method_helper(Klass* klass, const char* method_name, int method_name_len,
+ const char* signature_name, int signature_name_len);
+ // Resolution methods for aot compiled code.
+ static void resolve_string_by_symbol(JavaThread* current, void* string_result, const char* name);
+ static void resolve_dynamic_invoke(JavaThread* current, oop* appendix_result);
+
+ static Klass* resolve_klass_by_symbol(JavaThread* current, Klass** klass_result, const char* name);
+ static Klass* initialize_klass_by_symbol(JavaThread* current, Klass** klass_result, const char* name);
+ static MethodCounters* resolve_method_by_symbol_and_load_counters(JavaThread* current, MethodCounters** counters_result, Klass* klass_hint, const char* data);
+ static void invocation_event(JavaThread* current, MethodCounters* counters);
+ static void backedge_event(JavaThread* current, MethodCounters* counters, int branch_bci, int target_bci);
+};
+
+#endif // SHARE_JVMCI_COMPILERRUNTIME_HPP
diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp
index 3c8abb36e..2eff43b52 100644
--- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp
+++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -173,6 +173,70 @@ OopMap* CodeInstaller::create_oop_map(JVMCIObject debug_info, JVMCI_TRAPS) {
return map;
}
+#if INCLUDE_AOT
+AOTOopRecorder::AOTOopRecorder(CodeInstaller* code_inst, Arena* arena, bool deduplicate) : OopRecorder(arena, deduplicate) {
+ _code_inst = code_inst;
+ _meta_refs = new GrowableArray<jobject>();
+}
+
+int AOTOopRecorder::nr_meta_refs() const {
+ return _meta_refs->length();
+}
+
+jobject AOTOopRecorder::meta_element(int pos) const {
+ return _meta_refs->at(pos);
+}
+
+int AOTOopRecorder::find_index(Metadata* h) {
+ JavaThread* THREAD = JavaThread::current();
+ JVMCIEnv* JVMCIENV = _code_inst->jvmci_env();
+ int oldCount = metadata_count();
+ int index = this->OopRecorder::find_index(h);
+ int newCount = metadata_count();
+
+ if (oldCount == newCount) {
+ // found a match
+ return index;
+ }
+
+ vmassert(index + 1 == newCount, "must be last");
+
+ JVMCIKlassHandle klass(THREAD);
+ JVMCIObject result;
+ guarantee(h != NULL,
+ "If DebugInformationRecorder::describe_scope passes NULL oldCount == newCount must hold.");
+ if (h->is_klass()) {
+ klass = (Klass*) h;
+ result = JVMCIENV->get_jvmci_type(klass, JVMCI_CATCH);
+ } else if (h->is_method()) {
+ Method* method = (Method*) h;
+ methodHandle mh(THREAD, method);
+ result = JVMCIENV->get_jvmci_method(mh, JVMCI_CATCH);
+ }
+ jobject ref = JVMCIENV->get_jobject(result);
+ record_meta_ref(ref, index);
+
+ return index;
+}
+
+int AOTOopRecorder::find_index(jobject h) {
+ if (h == NULL) {
+ return 0;
+ }
+ oop javaMirror = JNIHandles::resolve(h);
+ Klass* klass = java_lang_Class::as_Klass(javaMirror);
+ return find_index(klass);
+}
+
+void AOTOopRecorder::record_meta_ref(jobject o, int index) {
+ assert(index > 0, "must be 1..n");
+ index -= 1; // reduce by one to convert to array index
+
+ assert(index == _meta_refs->length(), "must be last");
+ _meta_refs->append(o);
+}
+#endif // INCLUDE_AOT
+
void* CodeInstaller::record_metadata_reference(CodeSection* section, address dest, JVMCIObject constant, JVMCI_TRAPS) {
/*
* This method needs to return a raw (untyped) pointer, since the value of a pointer to the base
@@ -475,6 +539,69 @@ void CodeInstaller::initialize_dependencies(JVMCIObject compiled_code, OopRecord
}
}
+#if INCLUDE_AOT
+RelocBuffer::~RelocBuffer() {
+ FREE_C_HEAP_ARRAY(char, _buffer);
+}
+
+address RelocBuffer::begin() const {
+ if (_buffer != NULL) {
+ return (address) _buffer;
+ }
+ return (address) _static_buffer;
+}
+
+void RelocBuffer::set_size(size_t bytes) {
+ assert(bytes <= _size, "can't grow in size!");
+ _size = bytes;
+}
+
+void RelocBuffer::ensure_size(size_t bytes) {
+ assert(_buffer == NULL, "can only be used once");
+ assert(_size == 0, "can only be used once");
+ if (bytes >= RelocBuffer::stack_size) {
+ _buffer = NEW_C_HEAP_ARRAY(char, bytes, mtJVMCI);
+ }
+ _size = bytes;
+}
+
+JVMCI::CodeInstallResult CodeInstaller::gather_metadata(JVMCIObject target, JVMCIObject compiled_code, CodeMetadata& metadata, JVMCI_TRAPS) {
+ assert(JVMCIENV->is_hotspot(), "AOT code is executed only in HotSpot mode");
+ CodeBuffer buffer("JVMCI Compiler CodeBuffer for Metadata");
+ AOTOopRecorder* recorder = new AOTOopRecorder(this, &_arena, true);
+ initialize_dependencies(compiled_code, recorder, JVMCI_CHECK_OK);
+
+ metadata.set_oop_recorder(recorder);
+
+ // Get instructions and constants CodeSections early because we need it.
+ _instructions = buffer.insts();
+ _constants = buffer.consts();
+ buffer.set_immutable_PIC(_immutable_pic_compilation);
+
+ initialize_fields(target, compiled_code, JVMCI_CHECK_OK);
+ JVMCI::CodeInstallResult result = initialize_buffer(buffer, false, JVMCI_CHECK_OK);
+ if (result != JVMCI::ok) {
+ return result;
+ }
+
+ _debug_recorder->pcs_size(); // create the sentinel record
+
+ assert(_debug_recorder->pcs_length() >= 2, "must be at least 2");
+
+ metadata.set_pc_desc(_debug_recorder->pcs(), _debug_recorder->pcs_length());
+ metadata.set_scopes(_debug_recorder->stream()->buffer(), _debug_recorder->data_size());
+ metadata.set_exception_table(&_exception_handler_table);
+ metadata.set_implicit_exception_table(&_implicit_exception_table);
+
+ RelocBuffer* reloc_buffer = metadata.get_reloc_buffer();
+
+ reloc_buffer->ensure_size(buffer.total_relocation_size());
+ size_t size = (size_t) buffer.copy_relocations_to(reloc_buffer->begin(), (CodeBuffer::csize_t) reloc_buffer->size(), true);
+ reloc_buffer->set_size(size);
+ return JVMCI::ok;
+}
+#endif // INCLUDE_AOT
+
// constructor used to create a method
JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler,
JVMCIObject target,
@@ -494,6 +621,9 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler,
// Get instructions and constants CodeSections early because we need it.
_instructions = buffer.insts();
_constants = buffer.consts();
+#if INCLUDE_AOT
+ buffer.set_immutable_PIC(_immutable_pic_compilation);
+#endif
initialize_fields(target, compiled_code, JVMCI_CHECK_OK);
JVMCI::CodeInstallResult result = initialize_buffer(buffer, true, JVMCI_CHECK_OK);
@@ -615,8 +745,9 @@ void CodeInstaller::initialize_fields(JVMCIObject target, JVMCIObject compiled_c
}
int CodeInstaller::estimate_stubs_size(JVMCI_TRAPS) {
- // Estimate the number of static call stubs that might be emitted.
+ // Estimate the number of static and aot call stubs that might be emitted.
int static_call_stubs = 0;
+ int aot_call_stubs = 0;
int trampoline_stubs = 0;
JVMCIObjectArray sites = this->sites();
for (int i = 0; i < JVMCIENV->get_length(sites); i++) {
@@ -644,10 +775,22 @@ int CodeInstaller::estimate_stubs_size(JVMCI_TRAPS) {
}
}
}
+#if INCLUDE_AOT
+ if (UseAOT && jvmci_env()->isa_site_Call(site)) {
+ JVMCIObject target = jvmci_env()-> get_site_Call_target(site);
+ if (!jvmci_env()->isa_HotSpotForeignCallTarget(target)) {
+ // Add far aot trampolines.
+ aot_call_stubs++;
+ }
+ }
+#endif
}
}
int size = static_call_stubs * CompiledStaticCall::to_interp_stub_size();
size += trampoline_stubs * CompiledStaticCall::to_trampoline_stub_size();
+#if INCLUDE_AOT
+ size += aot_call_stubs * CompiledStaticCall::to_aot_stub_size();
+#endif
return size;
}
@@ -1137,6 +1280,10 @@ void CodeInstaller::site_Call(CodeBuffer& buffer, jint pc_offset, JVMCIObject si
if (foreign_call.is_non_null()) {
jlong foreign_call_destination = jvmci_env()->get_HotSpotForeignCallTarget_address(foreign_call);
+ if (_immutable_pic_compilation) {
+ // Use fake short distance during PIC compilation.
+ foreign_call_destination = (jlong)(_instructions->start() + pc_offset);
+ }
CodeInstaller::pd_relocate_ForeignCall(inst, foreign_call_destination, JVMCI_CHECK);
} else { // method != NULL
if (debug_info.is_null()) {
@@ -1151,6 +1298,10 @@ void CodeInstaller::site_Call(CodeBuffer& buffer, jint pc_offset, JVMCIObject si
JVMCI_ERROR("could not emit to_interp stub - code cache is full");
}
}
+#if INCLUDE_AOT
+ // Trampoline to far aot code.
+ CompiledStaticCall::emit_to_aot_stub(buffer, _instructions->start() + pc_offset);
+#endif
}
_next_call_type = INVOKE_INVALID;
@@ -1174,11 +1325,25 @@ void CodeInstaller::site_DataPatch(CodeBuffer& buffer, jint pc_offset, JVMCIObje
const char* to_string = JVMCIENV->as_utf8_string(string);
JVMCI_THROW_MSG(IllegalArgumentException, err_msg("Direct object constant reached the backend: %s", to_string));
}
- pd_patch_OopConstant(pc_offset, constant, JVMCI_CHECK);
+ if (!_immutable_pic_compilation) {
+ // Do not patch during PIC compilation.
+ pd_patch_OopConstant(pc_offset, constant, JVMCI_CHECK);
+ }
} else if (jvmci_env()->isa_IndirectHotSpotObjectConstantImpl(constant)) {
- pd_patch_OopConstant(pc_offset, constant, JVMCI_CHECK);
+ if (!_immutable_pic_compilation) {
+ // Do not patch during PIC compilation.
+ pd_patch_OopConstant(pc_offset, constant, JVMCI_CHECK);
+ }
} else if (jvmci_env()->isa_HotSpotMetaspaceConstantImpl(constant)) {
- pd_patch_MetaspaceConstant(pc_offset, constant, JVMCI_CHECK);
+ if (!_immutable_pic_compilation) {
+ pd_patch_MetaspaceConstant(pc_offset, constant, JVMCI_CHECK);
+ }
+#if INCLUDE_AOT
+ } else if (jvmci_env()->isa_HotSpotSentinelConstant(constant)) {
+ if (!_immutable_pic_compilation) {
+ JVMCI_ERROR("sentinel constant not supported for normal compiles: %s", jvmci_env()->klass_name(constant));
+ }
+#endif
} else {
JVMCI_ERROR("unknown constant type in data patch: %s", jvmci_env()->klass_name(constant));
}
diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp
index 2c8e231c7..5ac7769b8 100644
--- a/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp
+++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,42 @@
#include "jvmci/jvmci.hpp"
#include "jvmci/jvmciEnv.hpp"
+#if INCLUDE_AOT
+class RelocBuffer : public StackObj {
+ enum { stack_size = 1024 };
+public:
+ RelocBuffer() : _size(0), _buffer(0) {}
+ ~RelocBuffer();
+ void ensure_size(size_t bytes);
+ void set_size(size_t bytes);
+ address begin() const;
+ size_t size() const { return _size; }
+private:
+ size_t _size;
+ char _static_buffer[stack_size];
+ char *_buffer;
+};
+
+class CodeInstaller;
+
+class AOTOopRecorder : public OopRecorder {
+public:
+ AOTOopRecorder(CodeInstaller* code_inst, Arena* arena = NULL, bool deduplicate = false);
+
+ virtual int find_index(Metadata* h);
+ virtual int find_index(jobject h);
+ int nr_meta_refs() const;
+ jobject meta_element(int pos) const;
+
+private:
+ void record_meta_ref(jobject ref, int index);
+
+ GrowableArray<jobject>* _meta_refs;
+
+ CodeInstaller* _code_inst;
+};
+#endif // INCLUDE_AOT
+
class CodeMetadata {
public:
CodeMetadata() {}
@@ -42,6 +78,11 @@ public:
u_char* get_scopes_desc() const { return _scopes_desc; }
int get_scopes_size() const { return _nr_scopes_desc; }
+#if INCLUDE_AOT
+ RelocBuffer* get_reloc_buffer() { return &_reloc_buffer; }
+ AOTOopRecorder* get_oop_recorder() { return _oop_recorder; }
+#endif
+
ExceptionHandlerTable* get_exception_table() { return _exception_table; }
ImplicitExceptionTable* get_implicit_exception_table() { return _implicit_exception_table; }
@@ -56,6 +97,12 @@ public:
_nr_scopes_desc = size;
}
+#if INCLUDE_AOT
+ void set_oop_recorder(AOTOopRecorder* recorder) {
+ _oop_recorder = recorder;
+ }
+#endif
+
void set_exception_table(ExceptionHandlerTable* table) {
_exception_table = table;
}
@@ -72,6 +119,10 @@ private:
u_char* _scopes_desc;
int _nr_scopes_desc;
+#if INCLUDE_AOT
+ RelocBuffer _reloc_buffer;
+ AOTOopRecorder* _oop_recorder;
+#endif
ExceptionHandlerTable* _exception_table;
ImplicitExceptionTable* _implicit_exception_table;
};
@@ -151,6 +202,8 @@ private:
ImplicitExceptionTable _implicit_exception_table;
bool _has_auto_box;
+ bool _immutable_pic_compilation; // Installer is called for Immutable PIC compilation.
+
static ConstantOopWriteValue* _oop_null_scope_value;
static ConstantIntValue* _int_m1_scope_value;
static ConstantIntValue* _int_0_scope_value;
@@ -178,11 +231,15 @@ private:
public:
- CodeInstaller(JVMCIEnv* jvmci_env) :
+ CodeInstaller(JVMCIEnv* jvmci_env, bool immutable_pic_compilation) :
_arena(mtJVMCI),
_jvmci_env(jvmci_env),
- _has_auto_box(false) {}
+ _has_auto_box(false),
+ _immutable_pic_compilation(immutable_pic_compilation) {}
+#if INCLUDE_AOT
+ JVMCI::CodeInstallResult gather_metadata(JVMCIObject target, JVMCIObject compiled_code, CodeMetadata& metadata, JVMCI_TRAPS);
+#endif
JVMCI::CodeInstallResult install(JVMCICompiler* compiler,
JVMCIObject target,
JVMCIObject compiled_code,
diff --git a/src/hotspot/share/jvmci/jvmciCompiler.cpp b/src/hotspot/share/jvmci/jvmciCompiler.cpp
index faaab84d9..c5055e607 100644
--- a/src/hotspot/share/jvmci/jvmciCompiler.cpp
+++ b/src/hotspot/share/jvmci/jvmciCompiler.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -57,7 +57,7 @@ JVMCICompiler* JVMCICompiler::instance(bool require_non_null, TRAPS) {
// Initialization
void JVMCICompiler::initialize() {
- assert(!CompilerConfig::is_c1_or_interpreter_only_no_jvmci(), "JVMCI is launched, it's not c1/interpreter only mode");
+ assert(!CompilerConfig::is_c1_or_interpreter_only_no_aot_or_jvmci(), "JVMCI is launched, it's not c1/interpreter only mode");
if (!UseCompiler || !EnableJVMCI || !UseJVMCICompiler || !should_perform_init()) {
return;
}
diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
index decedf67b..42b4a07da 100644
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -886,9 +886,10 @@ C2V_VMENTRY_0(jint, installCode, (JNIEnv *env, jobject, jobject target, jobject
JVMCICompiler* compiler = JVMCICompiler::instance(true, CHECK_JNI_ERR);
TraceTime install_time("installCode", JVMCICompiler::codeInstallTimer(!thread->is_Compiler_thread()));
+ bool is_immutable_PIC = JVMCIENV->get_HotSpotCompiledCode_isImmutablePIC(compiled_code_handle) > 0;
nmethodLocker nmethod_handle;
- CodeInstaller installer(JVMCIENV);
+ CodeInstaller installer(JVMCIENV, is_immutable_PIC);
JVMCI::CodeInstallResult result = installer.install(compiler,
target_handle,
compiled_code_handle,
@@ -931,7 +932,85 @@ C2V_VMENTRY_0(jint, installCode, (JNIEnv *env, jobject, jobject target, jobject
C2V_END
C2V_VMENTRY_0(jint, getMetadata, (JNIEnv *env, jobject, jobject target, jobject compiled_code, jobject metadata))
+#if INCLUDE_AOT
+ HandleMark hm(THREAD);
+ assert(JVMCIENV->is_hotspot(), "AOT code is executed only in HotSpot mode");
+
+ JVMCIObject target_handle = JVMCIENV->wrap(target);
+ JVMCIObject compiled_code_handle = JVMCIENV->wrap(compiled_code);
+ JVMCIObject metadata_handle = JVMCIENV->wrap(metadata);
+
+ CodeMetadata code_metadata;
+
+ CodeInstaller installer(JVMCIENV, true /* immutable PIC compilation */);
+ JVMCI::CodeInstallResult result = installer.gather_metadata(target_handle, compiled_code_handle, code_metadata, JVMCI_CHECK_0);
+ if (result != JVMCI::ok) {
+ return result;
+ }
+
+ if (code_metadata.get_nr_pc_desc() > 0) {
+ int size = sizeof(PcDesc) * code_metadata.get_nr_pc_desc();
+ JVMCIPrimitiveArray array = JVMCIENV->new_byteArray(size, JVMCI_CHECK_(JVMCI::cache_full));
+ JVMCIENV->copy_bytes_from((jbyte*) code_metadata.get_pc_desc(), array, 0, size);
+ HotSpotJVMCI::HotSpotMetaData::set_pcDescBytes(JVMCIENV, metadata_handle, array);
+ }
+
+ if (code_metadata.get_scopes_size() > 0) {
+ int size = code_metadata.get_scopes_size();
+ JVMCIPrimitiveArray array = JVMCIENV->new_byteArray(size, JVMCI_CHECK_(JVMCI::cache_full));
+ JVMCIENV->copy_bytes_from((jbyte*) code_metadata.get_scopes_desc(), array, 0, size);
+ HotSpotJVMCI::HotSpotMetaData::set_scopesDescBytes(JVMCIENV, metadata_handle, array);
+ }
+
+ RelocBuffer* reloc_buffer = code_metadata.get_reloc_buffer();
+ int size = (int) reloc_buffer->size();
+ JVMCIPrimitiveArray array = JVMCIENV->new_byteArray(size, JVMCI_CHECK_(JVMCI::cache_full));
+ JVMCIENV->copy_bytes_from((jbyte*) reloc_buffer->begin(), array, 0, size);
+ HotSpotJVMCI::HotSpotMetaData::set_relocBytes(JVMCIENV, metadata_handle, array);
+
+ const OopMapSet* oopMapSet = installer.oopMapSet();
+ {
+ ResourceMark mark;
+ ImmutableOopMapBuilder builder(oopMapSet);
+ int size = builder.heap_size();
+ JVMCIPrimitiveArray array = JVMCIENV->new_byteArray(size, JVMCI_CHECK_(JVMCI::cache_full));
+ builder.generate_into((address) HotSpotJVMCI::resolve(array)->byte_at_addr(0));
+ HotSpotJVMCI::HotSpotMetaData::set_oopMaps(JVMCIENV, metadata_handle, array);
+ }
+
+ AOTOopRecorder* recorder = code_metadata.get_oop_recorder();
+
+ int nr_meta_refs = recorder->nr_meta_refs();
+ JVMCIObjectArray metadataArray = JVMCIENV->new_Object_array(nr_meta_refs, JVMCI_CHECK_(JVMCI::cache_full));
+ for (int i = 0; i < nr_meta_refs; ++i) {
+ jobject element = recorder->meta_element(i);
+ if (element == NULL) {
+ return JVMCI::cache_full;
+ }
+ JVMCIENV->put_object_at(metadataArray, i, JVMCIENV->wrap(element));
+ }
+ HotSpotJVMCI::HotSpotMetaData::set_metadata(JVMCIENV, metadata_handle, metadataArray);
+
+ ExceptionHandlerTable* handler = code_metadata.get_exception_table();
+ int table_size = handler->size_in_bytes();
+ JVMCIPrimitiveArray exceptionArray = JVMCIENV->new_byteArray(table_size, JVMCI_CHECK_(JVMCI::cache_full));
+ if (table_size > 0) {
+ handler->copy_bytes_to((address) HotSpotJVMCI::resolve(exceptionArray)->byte_at_addr(0));
+ }
+ HotSpotJVMCI::HotSpotMetaData::set_exceptionBytes(JVMCIENV, metadata_handle, exceptionArray);
+
+ ImplicitExceptionTable* implicit = code_metadata.get_implicit_exception_table();
+ int implicit_table_size = implicit->size_in_bytes();
+ JVMCIPrimitiveArray implicitExceptionArray = JVMCIENV->new_byteArray(implicit_table_size, JVMCI_CHECK_(JVMCI::cache_full));
+ if (implicit_table_size > 0) {
+ implicit->copy_bytes_to((address) HotSpotJVMCI::resolve(implicitExceptionArray)->byte_at_addr(0), implicit_table_size);
+ }
+ HotSpotJVMCI::HotSpotMetaData::set_implicitExceptionBytes(JVMCIENV, metadata_handle, implicitExceptionArray);
+
+ return result;
+#else
JVMCI_THROW_MSG_0(InternalError, "unimplemented");
+#endif
C2V_END
C2V_VMENTRY(void, resetCompilationStatistics, (JNIEnv* env, jobject))
@@ -1578,7 +1657,16 @@ C2V_VMENTRY_0(jint, methodDataProfileDataSize, (JNIEnv* env, jobject, jlong meta
C2V_END
C2V_VMENTRY_0(jlong, getFingerprint, (JNIEnv* env, jobject, jlong metaspace_klass))
+#if INCLUDE_AOT
+ Klass *k = (Klass*) (address) metaspace_klass;
+ if (k->is_instance_klass()) {
+ return InstanceKlass::cast(k)->get_stored_fingerprint();
+ } else {
+ return 0;
+ }
+#else
JVMCI_THROW_MSG_0(InternalError, "unimplemented");
+#endif
C2V_END
C2V_VMENTRY_NULL(jobject, getInterfaces, (JNIEnv* env, jobject, jobject jvmci_type))
diff --git a/src/hotspot/share/jvmci/vmStructs_compiler_runtime.hpp b/src/hotspot/share/jvmci/vmStructs_compiler_runtime.hpp
new file mode 100644
index 000000000..07ccfe06e
--- /dev/null
+++ b/src/hotspot/share/jvmci/vmStructs_compiler_runtime.hpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef SHARE_JVMCI_VMSTRUCTS_COMPILER_RUNTIME_HPP
+#define SHARE_JVMCI_VMSTRUCTS_COMPILER_RUNTIME_HPP
+
+#if INCLUDE_AOT
+#include "jvmci/compilerRuntime.hpp"
+
+#define VM_ADDRESSES_COMPILER_RUNTIME(declare_address, declare_preprocessor_address, declare_function) \
+ declare_function(CompilerRuntime::resolve_dynamic_invoke) \
+ declare_function(CompilerRuntime::resolve_string_by_symbol) \
+ declare_function(CompilerRuntime::resolve_klass_by_symbol) \
+ declare_function(CompilerRuntime::resolve_method_by_symbol_and_load_counters) \
+ declare_function(CompilerRuntime::initialize_klass_by_symbol) \
+ declare_function(CompilerRuntime::invocation_event) \
+ declare_function(CompilerRuntime::backedge_event)
+
+#else // INCLUDE_AOT
+
+#define VM_ADDRESSES_COMPILER_RUNTIME(declare_address, declare_preprocessor_address, declare_function)
+
+#endif // INCLUDE_AOT
+
+#endif // SHARE_JVMCI_VMSTRUCTS_COMPILER_RUNTIME_HPP
diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp
index 3f57d487b..3cd545532 100644
--- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp
+++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
#include "jvmci/jvmciCodeInstaller.hpp"
#include "jvmci/jvmciCompilerToVM.hpp"
#include "jvmci/jvmciRuntime.hpp"
+#include "jvmci/vmStructs_compiler_runtime.hpp"
#include "jvmci/vmStructs_jvmci.hpp"
#include "oops/klassVtable.hpp"
#include "oops/objArrayKlass.hpp"
@@ -234,6 +235,7 @@
JVMTI_ONLY(nonstatic_field(MethodCounters, _number_of_breakpoints, u2)) \
nonstatic_field(MethodCounters, _invocation_counter, InvocationCounter) \
nonstatic_field(MethodCounters, _backedge_counter, InvocationCounter) \
+ AOT_ONLY(nonstatic_field(MethodCounters, _method, Method*)) \
\
nonstatic_field(MethodData, _size, int) \
nonstatic_field(MethodData, _method, Method*) \
@@ -870,6 +872,9 @@ VMAddressEntry JVMCIVMStructs::localHotSpotVMAddresses[] = {
VM_ADDRESSES(GENERATE_VM_ADDRESS_ENTRY,
GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY,
GENERATE_VM_FUNCTION_ENTRY)
+ VM_ADDRESSES_COMPILER_RUNTIME(GENERATE_VM_ADDRESS_ENTRY,
+ GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY,
+ GENERATE_VM_FUNCTION_ENTRY)
VM_ADDRESSES_OS(GENERATE_VM_ADDRESS_ENTRY,
GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY,
GENERATE_VM_FUNCTION_ENTRY)
diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp
index d8ae64bc8..8bcdd16a7 100644
--- a/src/hotspot/share/logging/logTag.hpp
+++ b/src/hotspot/share/logging/logTag.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@
LOG_TAG(age) \
LOG_TAG(alloc) \
LOG_TAG(annotation) \
- JBOOSTER_ONLY(LOG_TAG(aot)) \
+ AOT_ONLY(LOG_TAG(aot)) \
LOG_TAG(arguments) \
LOG_TAG(attach) \
LOG_TAG(barrier) \
@@ -45,7 +45,7 @@
LOG_TAG(bot) \
LOG_TAG(breakpoint) \
LOG_TAG(bytecode) \
- LOG_TAG(cds) \
+ CDS_ONLY(LOG_TAG(cds)) \
LOG_TAG(census) \
LOG_TAG(class) \
LOG_TAG(classhisto) \
diff --git a/src/hotspot/share/memory/heap.hpp b/src/hotspot/share/memory/heap.hpp
index 7405cfe59..155bf4446 100644
--- a/src/hotspot/share/memory/heap.hpp
+++ b/src/hotspot/share/memory/heap.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -171,7 +171,16 @@ class CodeHeap : public CHeapObj<mtCode> {
// Containment means "contained in committed space".
bool contains(const void* p) const { return low() <= p && p < high(); }
bool contains_blob(const CodeBlob* blob) const {
- return contains((void*)blob);
+ // AOT CodeBlobs (i.e. AOTCompiledMethod) objects aren't allocated in the AOTCodeHeap but on the C-Heap.
+ // Only the code they are pointing to is located in the AOTCodeHeap. All other CodeBlobs are allocated
+ // directly in their corresponding CodeHeap with their code appended to the actual C++ object.
+ // So all CodeBlobs except AOTCompiledMethod are continuous in memory with their data and code while
+ // AOTCompiledMethod and their code/data is distributed in the C-Heap. This means we can use the
+ // address of a CodeBlob object in order to locate it in its heap while we have to use the address
+ // of the actual code an AOTCompiledMethod object is pointing to in order to locate it.
+ // Notice that for an ordinary CodeBlob with code size zero, code_begin() may point beyond the object!
+ const void* start = AOT_ONLY( (code_blob_type() == CodeBlobType::AOT) ? blob->code_begin() : ) (void*)blob;
+ return contains(start);
}
virtual void* find_start(void* p) const; // returns the block containing p or NULL
diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp
index 1e897615e..7e5898e6d 100644
--- a/src/hotspot/share/memory/metaspace.cpp
+++ b/src/hotspot/share/memory/metaspace.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2017, 2021 SAP SE. All rights reserved.
+ * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2023 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -57,7 +57,9 @@
#include "utilities/debug.hpp"
#include "utilities/formatBuffer.hpp"
#include "utilities/globalDefinitions.hpp"
-
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
using metaspace::ChunkManager;
using metaspace::CommitLimiter;
using metaspace::MetaspaceContext;
diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp
index 8ba5fae9c..31d86d95a 100644
--- a/src/hotspot/share/memory/universe.cpp
+++ b/src/hotspot/share/memory/universe.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -79,6 +79,9 @@
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
#include "utilities/preserveException.hpp"
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
// Known objects
Klass* Universe::_typeArrayKlassObjs[T_LONG+1] = { NULL /*, NULL...*/ };
@@ -743,6 +746,10 @@ jint universe_init() {
// Initialize performance counters for metaspaces
MetaspaceCounters::initialize_performance_counters();
+#if INCLUDE_AOT
+ AOTLoader::universe_init();
+#endif
+
// Checks 'AfterMemoryInit' constraints.
if (!JVMFlagLimit::check_all_constraints(JVMFlagConstraintPhase::AfterMemoryInit)) {
return JNI_EINVAL;
diff --git a/src/hotspot/share/memory/virtualspace.hpp b/src/hotspot/share/memory/virtualspace.hpp
index a3b8683d3..4dece6743 100644
--- a/src/hotspot/share/memory/virtualspace.hpp
+++ b/src/hotspot/share/memory/virtualspace.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -209,6 +209,14 @@ class VirtualSpace {
char* low_boundary() const { return _low_boundary; }
char* high_boundary() const { return _high_boundary; }
+#if INCLUDE_AOT
+ // Set boundaries for code section in AOT library.
+ void set_low_boundary(char *p) { _low_boundary = p; }
+ void set_high_boundary(char *p) { _high_boundary = p; }
+ void set_low(char *p) { _low = p; }
+ void set_high(char *p) { _high = p; }
+#endif
+
bool special() const { return _special; }
public:
diff --git a/src/hotspot/share/oops/compressedOops.cpp b/src/hotspot/share/oops/compressedOops.cpp
index bb050673e..03dbf5966 100644
--- a/src/hotspot/share/oops/compressedOops.cpp
+++ b/src/hotspot/share/oops/compressedOops.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,9 @@
#include "gc/shared/collectedHeap.hpp"
#include "runtime/arguments.hpp"
#include "runtime/globals.hpp"
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
// For UseCompressedOops.
NarrowPtrStruct CompressedOops::_narrow_oop = { NULL, 0, true };
@@ -64,6 +67,10 @@ void CompressedOops::initialize(const ReservedHeapSpace& heap_space) {
set_base((address)heap_space.compressed_oop_base());
}
+#if INCLUDE_AOT
+ AOTLoader::set_narrow_oop_shift();
+#endif
+
_heap_address_range = heap_space.region();
LogTarget(Debug, gc, heap, coops) lt;
@@ -260,6 +267,12 @@ void CompressedKlassPointers::initialize(address addr, size_t len) {
set_base(base);
set_shift(shift);
set_range(range);
+
+#if INCLUDE_AOT
+ // Note: this may modify our shift.
+ AOTLoader::set_narrow_klass_shift();
+#endif // INCLUDE_AOT
+
#else
fatal("64bit only.");
#endif
diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp
index 47c4d31c1..462505851 100644
--- a/src/hotspot/share/oops/instanceKlass.cpp
+++ b/src/hotspot/share/oops/instanceKlass.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -95,7 +95,9 @@
#if INCLUDE_JFR
#include "jfr/jfrEvents.hpp"
#endif
-
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
#ifdef DTRACE_ENABLED
@@ -426,7 +428,8 @@ InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& par
const int size = InstanceKlass::size(parser.vtable_size(),
parser.itable_size(),
nonstatic_oop_map_size(parser.total_oop_map_count()),
- parser.is_interface());
+ parser.is_interface(),
+ AOT_ONLY(should_store_fingerprint(parser.is_hidden())) NOT_AOT(false));
const Symbol* const class_name = parser.class_name();
assert(class_name != NULL, "invariant");
@@ -1170,6 +1173,11 @@ void InstanceKlass::initialize_impl(TRAPS) {
}
+#if INCLUDE_AOT
+ // Look for aot compiled methods for this klass, including class initializer.
+ AOTLoader::load_for_klass(this, THREAD);
+#endif
+
// Step 8
{
DTRACE_CLASSINIT_PROBE_WAIT(clinit, -1, wait);
@@ -2391,6 +2399,84 @@ void InstanceKlass::clean_method_data() {
}
}
+#if INCLUDE_AOT
+bool InstanceKlass::supers_have_passed_fingerprint_checks() {
+ if (java_super() != NULL && !java_super()->has_passed_fingerprint_check()) {
+ ResourceMark rm;
+ log_trace(class, fingerprint)("%s : super %s not fingerprinted", external_name(), java_super()->external_name());
+ return false;
+ }
+
+ Array<InstanceKlass*>* local_interfaces = this->local_interfaces();
+ if (local_interfaces != NULL) {
+ int length = local_interfaces->length();
+ for (int i = 0; i < length; i++) {
+ InstanceKlass* intf = local_interfaces->at(i);
+ if (!intf->has_passed_fingerprint_check()) {
+ ResourceMark rm;
+ log_trace(class, fingerprint)("%s : interface %s not fingerprinted", external_name(), intf->external_name());
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+u1 InstanceKlass::get_aot_flags() const {
+ address adr = adr_aot_flags();
+ return (u1)(*adr);
+}
+
+void InstanceKlass::set_aot_flags(u1 aot_flags) {
+ address adr = adr_aot_flags();
+ *(u1*)adr = aot_flags;
+}
+
+
+bool InstanceKlass::should_store_fingerprint(bool is_hidden) {
+ // We store the fingerprint into the InstanceKlass only in the following 2 cases:
+ if (CalculateClassFingerprint) {
+ // (1) We are running AOT to generate a shared library.
+ return true;
+ }
+ if (Arguments::is_dumping_archive()) {
+ // (2) We are running -Xshare:dump or -XX:ArchiveClassesAtExit to create a shared archive
+ return true;
+ }
+ if (UseAOT && is_hidden) {
+ // (3) We are using AOT code from a shared library and see a hidden class
+ return true;
+ }
+
+ // In all other cases we might set the _has_passed_fingerprint_check bit,
+ // but do not store the 64-bit fingerprint to save space.
+ return false;
+}
+
+bool InstanceKlass::has_stored_fingerprint() const {
+ return should_store_fingerprint() || is_shared();
+}
+
+uint64_t InstanceKlass::get_stored_fingerprint() const {
+ address adr = adr_fingerprint();
+ if (adr != NULL) {
+ return (uint64_t)Bytes::get_native_u8(adr); // adr may not be 64-bit aligned
+ }
+ return 0;
+}
+
+void InstanceKlass::store_fingerprint(uint64_t fingerprint) {
+ address adr = adr_fingerprint();
+ if (adr != NULL) {
+ Bytes::put_native_u8(adr, (u8)fingerprint); // adr may not be 64-bit aligned
+
+ ResourceMark rm;
+ log_trace(class, fingerprint)("stored as " PTR64_FORMAT " for class %s", fingerprint, external_name());
+ }
+}
+#endif
+
void InstanceKlass::metaspace_pointers_do(MetaspaceClosure* it) {
Klass::metaspace_pointers_do(it);
diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp
index c111a6ab5..047b81a0c 100644
--- a/src/hotspot/share/oops/instanceKlass.hpp
+++ b/src/hotspot/share/oops/instanceKlass.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -50,6 +50,8 @@ class RecordComponent;
// The embedded nonstatic oop-map blocks are short pairs (offset, length)
// indicating where oops are located in instances of this klass.
// [EMBEDDED implementor of the interface] only exist for interface
+// [EMBEDDED fingerprint] only if should_store_fingerprint() == true
+// [EMBEDDED aot_flags ] only if INCLUDE_AOT == true
// forward declaration for class -- see below for definition
@@ -329,6 +331,13 @@ class InstanceKlass: public Klass {
static bool _disable_method_binary_search;
+#if INCLUDE_AOT
+ enum {
+ _aot_has_passed_fingerprint_check = 1 << 0 // when this class was loaded, the fingerprint computed from its
+ // code source was found to be matching the value recorded by AOT.
+ };
+#endif
+
public:
// The three BUILTIN class loader types
bool is_shared_boot_class() const {
@@ -775,6 +784,30 @@ public:
_misc_flags |= _misc_has_been_redefined;
}
+#if INCLUDE_AOT
+ bool has_passed_fingerprint_check() const {
+ return (get_aot_flags() & _aot_has_passed_fingerprint_check) != 0;
+ }
+ void set_has_passed_fingerprint_check(bool b) {
+ u1 aot_flags = get_aot_flags();
+ if (b) {
+ aot_flags |= _aot_has_passed_fingerprint_check;
+ } else {
+ aot_flags &= ~_aot_has_passed_fingerprint_check;
+ }
+ set_aot_flags(aot_flags);
+ }
+ bool supers_have_passed_fingerprint_checks();
+ u1 get_aot_flags() const;
+ void set_aot_flags(u1 aot_flags);
+
+ static bool should_store_fingerprint(bool is_hidden);
+ bool should_store_fingerprint() const { return should_store_fingerprint(is_hidden()); }
+ bool has_stored_fingerprint() const;
+ uint64_t get_stored_fingerprint() const;
+ void store_fingerprint(uint64_t fingerprint);
+#endif
+
bool is_scratch_class() const {
return (_misc_flags & _misc_is_scratch_class) != 0;
}
@@ -1032,18 +1065,21 @@ public:
static int size(int vtable_length, int itable_length,
int nonstatic_oop_map_size,
- bool is_interface) {
+ bool is_interface, bool has_stored_fingerprint) {
return align_metadata_size(header_size() +
vtable_length +
itable_length +
nonstatic_oop_map_size +
- (is_interface ? (int)sizeof(Klass*)/wordSize : 0));
+ (is_interface ? (int)sizeof(Klass*)/wordSize : 0) +
+ (has_stored_fingerprint ? (int)sizeof(uint64_t*)/wordSize : 0) +
+ AOT_ONLY(sizeof(u1)) NOT_AOT(0));
}
int size() const { return size(vtable_length(),
itable_length(),
nonstatic_oop_map_size(),
- is_interface());
+ is_interface(),
+ AOT_ONLY(has_stored_fingerprint()) NOT_AOT(false));
}
@@ -1056,6 +1092,10 @@ public:
inline Klass** end_of_nonstatic_oop_maps() const;
inline InstanceKlass* volatile* adr_implementor() const;
+#if INCLUDE_AOT
+ inline address adr_fingerprint() const;
+ inline address adr_aot_flags() const ;
+#endif
// Use this to return the size of an instance in heap words:
int size_helper() const {
@@ -1277,12 +1317,6 @@ public:
#if INCLUDE_JBOOSTER
bool is_dynamic_proxy() const;
-
- // [JBOOSTER TODO] aot
- bool should_store_fingerprint() const { return true; }
- bool has_stored_fingerprint() const { return true; }
- uint64_t get_stored_fingerprint() const { return 0u; }
- void store_fingerprint(uint64_t fingerprint) {}
#endif // INCLUDE_JBOOSTER
};
diff --git a/src/hotspot/share/oops/instanceKlass.inline.hpp b/src/hotspot/share/oops/instanceKlass.inline.hpp
index 8b6e2c335..192c2bb9e 100644
--- a/src/hotspot/share/oops/instanceKlass.inline.hpp
+++ b/src/hotspot/share/oops/instanceKlass.inline.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -62,6 +62,35 @@ inline InstanceKlass* volatile* InstanceKlass::adr_implementor() const {
}
}
+#if INCLUDE_AOT
+inline address InstanceKlass::adr_fingerprint() const {
+ if (has_stored_fingerprint()) {
+ InstanceKlass* volatile* adr_impl = adr_implementor();
+ if (adr_impl != NULL) {
+ return (address)(adr_impl + 1);
+ } else {
+ return (address)end_of_nonstatic_oop_maps();
+ }
+ } else {
+ return NULL;
+ }
+}
+
+inline u1* InstanceKlass::adr_aot_flags() const {
+ address fingerprint = adr_fingerprint();
+ if (fingerprint != NULL) {
+ return (u1*)(fingerprint + sizeof(uint64_t));
+ }
+
+ InstanceKlass* volatile* adr_impl = adr_implementor();
+ if (adr_impl != NULL) {
+ return (u1*)(adr_impl + 1);
+ } else {
+ return (u1*)end_of_nonstatic_oop_maps();
+ }
+}
+#endif
+
inline ObjArrayKlass* InstanceKlass::array_klasses_acquire() const {
return Atomic::load_acquire(&_array_klasses);
}
diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp
index d3e77ba70..1155f33a4 100644
--- a/src/hotspot/share/oops/method.hpp
+++ b/src/hotspot/share/oops/method.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -116,6 +116,10 @@ class Method : public Metadata {
CompiledMethod* volatile _code; // Points to the corresponding piece of native code
volatile address _from_interpreted_entry; // Cache of _code ? _adapter->i2c_entry() : _i2i_entry
+#if INCLUDE_AOT
+ CompiledMethod* _aot_code;
+#endif
+
// Constructor
Method(ConstMethod* xconst, AccessFlags access_flags);
public:
@@ -401,6 +405,18 @@ class Method : public Metadata {
}
}
+#if INCLUDE_AOT
+ void set_aot_code(CompiledMethod* aot_code) {
+ _aot_code = aot_code;
+ }
+
+ CompiledMethod* aot_code() const {
+ return _aot_code;
+ }
+#else
+ CompiledMethod* aot_code() const { return NULL; }
+#endif // INCLUDE_AOT
+
int nmethod_age() const {
if (method_counters() == NULL) {
return INT_MAX;
@@ -659,6 +675,8 @@ public:
// simultaneously. Use with caution.
bool has_compiled_code() const;
+ bool has_aot_code() const { return aot_code() != NULL; }
+
bool needs_clinit_barrier() const;
// sizing
diff --git a/src/hotspot/share/oops/methodCounters.cpp b/src/hotspot/share/oops/methodCounters.cpp
index 67b2ef960..23a6c91b9 100644
--- a/src/hotspot/share/oops/methodCounters.cpp
+++ b/src/hotspot/share/oops/methodCounters.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,11 +23,15 @@
*/
#include "precompiled.hpp"
#include "compiler/compiler_globals.hpp"
+#include "memory/metaspaceClosure.hpp"
#include "oops/method.hpp"
#include "oops/methodCounters.hpp"
#include "runtime/handles.inline.hpp"
MethodCounters::MethodCounters(const methodHandle& mh) :
+#if INCLUDE_AOT
+ _method(mh()),
+#endif
_prev_time(0),
_rate(0),
_nmethod_age(INT_MAX),
@@ -73,6 +77,13 @@ void MethodCounters::clear_counters() {
set_highest_osr_comp_level(0);
}
+void MethodCounters::metaspace_pointers_do(MetaspaceClosure* it) {
+ log_trace(cds)("Iter(MethodCounters): %p", this);
+#if INCLUDE_AOT
+ it->push(&_method);
+#endif
+}
+
void MethodCounters::print_value_on(outputStream* st) const {
assert(is_methodCounters(), "must be methodCounters");
st->print("method counters");
diff --git a/src/hotspot/share/oops/methodCounters.hpp b/src/hotspot/share/oops/methodCounters.hpp
index 2698ce3d3..b75b50e31 100644
--- a/src/hotspot/share/oops/methodCounters.hpp
+++ b/src/hotspot/share/oops/methodCounters.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,11 @@ class MethodCounters : public Metadata {
private:
InvocationCounter _invocation_counter; // Incremented before each activation of the method - used to trigger frequency-based optimizations
InvocationCounter _backedge_counter; // Incremented before each backedge taken - used to trigger frequency-based optimizations
+ // If you add a new field that points to any metaspace object, you
+ // must add this field to MethodCounters::metaspace_pointers_do().
+#if INCLUDE_AOT
+ Method* _method; // Back link to Method
+#endif
jlong _prev_time; // Previous time the rate was acquired
float _rate; // Events (invocation and backedge counter increments) per millisecond
int _nmethod_age;
@@ -69,12 +74,15 @@ class MethodCounters : public Metadata {
void deallocate_contents(ClassLoaderData* loader_data) {}
+ AOT_ONLY(Method* method() const { return _method; })
+
static int method_counters_size() {
return align_up((int)sizeof(MethodCounters), wordSize) / wordSize;
}
virtual int size() const {
return method_counters_size();
}
+ void metaspace_pointers_do(MetaspaceClosure* it);
MetaspaceObj::Type type() const { return MethodCountersType; }
void clear_counters();
diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp
index 473684107..13de7651e 100644
--- a/src/hotspot/share/opto/c2compiler.cpp
+++ b/src/hotspot/share/opto/c2compiler.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -79,7 +79,7 @@ bool C2Compiler::init_c2_runtime() {
}
void C2Compiler::initialize() {
- assert(!CompilerConfig::is_c1_or_interpreter_only_no_jvmci(), "C2 compiler is launched, it's not c1/interpreter only mode");
+ assert(!CompilerConfig::is_c1_or_interpreter_only_no_aot_or_jvmci(), "C2 compiler is launched, it's not c1/interpreter only mode");
// The first compiler thread that gets here will initialize the
// small amount of global state (and runtime stubs) that C2 needs.
diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp
index 8a1ed0d31..cab6d0067 100644
--- a/src/hotspot/share/opto/output.cpp
+++ b/src/hotspot/share/opto/output.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -575,6 +575,10 @@ void PhaseOutput::shorten_branches(uint* blk_starts) {
if (mcall->is_MachCallJava() && mcall->as_MachCallJava()->_method) {
stub_size += CompiledStaticCall::to_interp_stub_size();
reloc_size += CompiledStaticCall::reloc_to_interp_stub();
+#if INCLUDE_AOT
+ stub_size += CompiledStaticCall::to_aot_stub_size();
+ reloc_size += CompiledStaticCall::reloc_to_aot_stub();
+#endif
}
} else if (mach->is_MachSafePoint()) {
// If call/safepoint are adjacent, account for possible
diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp
index 5922dd979..c4c03ab8d 100644
--- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp
+++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -63,6 +63,9 @@
#include "runtime/safepointVerifiers.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/events.hpp"
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
Array<Method*>* VM_RedefineClasses::_old_methods = NULL;
Array<Method*>* VM_RedefineClasses::_new_methods = NULL;
@@ -4421,6 +4424,18 @@ void VM_RedefineClasses::redefine_single_class(Thread* current, jclass the_jclas
// Scratch class is unloaded but still needs cleaning, and skipping for CDS.
scratch_class->set_is_scratch_class();
+#if INCLUDE_AOT
+ // Replace fingerprint data
+ the_class->set_has_passed_fingerprint_check(scratch_class->has_passed_fingerprint_check());
+ the_class->store_fingerprint(scratch_class->get_stored_fingerprint());
+
+ if (!the_class->should_be_initialized()) {
+ // Class was already initialized, so AOT has only seen the original version.
+ // We need to let AOT look at it again.
+ AOTLoader::load_for_klass(the_class, current->as_Java_thread());
+ }
+#endif
+
// keep track of previous versions of this class
the_class->add_previous_version(scratch_class, emcp_method_count);
diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp
index 68228f514..0de584980 100644
--- a/src/hotspot/share/prims/jvmtiTagMap.cpp
+++ b/src/hotspot/share/prims/jvmtiTagMap.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -2628,7 +2628,7 @@ inline bool VM_HeapWalkOperation::iterate_over_class(oop java_class) {
} else if (tag.is_klass()) {
entry = pool->resolved_klass_at(i)->java_mirror();
} else {
- // Code generated by JIT compilers might not resolve constant
+ // Code generated by JIT and AOT compilers might not resolve constant
// pool entries. Treat them as resolved if they are loaded.
assert(tag.is_unresolved_klass(), "must be");
constantPoolHandle cp(Thread::current(), pool);
diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp
index 5466ff988..86a9493a9 100644
--- a/src/hotspot/share/prims/whitebox.cpp
+++ b/src/hotspot/share/prims/whitebox.cpp
@@ -113,6 +113,9 @@
#include "jvmci/jvmciEnv.hpp"
#include "jvmci/jvmciRuntime.hpp"
#endif
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif // INCLUDE_AOT
#ifdef LINUX
#include "os_linux.hpp"
@@ -1411,6 +1414,9 @@ WB_END
int WhiteBox::get_blob_type(const CodeBlob* code) {
guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled");
+ if (code->is_aot()) {
+ return -1;
+ }
return CodeCache::get_code_heap(code)->code_blob_type();
}
@@ -1468,7 +1474,7 @@ WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jbo
return result;
}
int comp_level = code->comp_level();
- int insts_size = code->insts_size();
+ int insts_size = comp_level == CompLevel_aot ? code->code_end() - code->code_begin() : code->insts_size();
ThreadToNativeFromVM ttn(thread);
jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string());
@@ -2257,6 +2263,14 @@ WB_ENTRY(jint, WB_ProtectionDomainRemovedCount(JNIEnv* env, jobject o))
return (jint) SystemDictionary::pd_cache_table()->removed_entries_count();
WB_END
+WB_ENTRY(jint, WB_AotLibrariesCount(JNIEnv* env, jobject o))
+ jint result = 0;
+#if INCLUDE_AOT
+ result = (jint) AOTLoader::heaps_count();
+#endif
+ return result;
+WB_END
+
WB_ENTRY(jint, WB_GetKlassMetadataSize(JNIEnv* env, jobject wb, jclass mirror))
Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve(mirror));
// Return size in bytes.
@@ -2620,6 +2634,7 @@ static JNINativeMethod methods[] = {
{CC"disableElfSectionCache", CC"()V", (void*)&WB_DisableElfSectionCache },
{CC"resolvedMethodItemsCount", CC"()J", (void*)&WB_ResolvedMethodItemsCount },
{CC"protectionDomainRemovedCount", CC"()I", (void*)&WB_ProtectionDomainRemovedCount },
+ {CC"aotLibrariesCount", CC"()I", (void*)&WB_AotLibrariesCount },
{CC"getKlassMetadataSize", CC"(Ljava/lang/Class;)I",(void*)&WB_GetKlassMetadataSize},
{CC"createMetaspaceTestContext", CC"(JJ)J", (void*)&WB_CreateMetaspaceTestContext},
diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp
index cd8e239f0..a7e3e22ab 100644
--- a/src/hotspot/share/runtime/abstract_vm_version.cpp
+++ b/src/hotspot/share/runtime/abstract_vm_version.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -128,13 +128,17 @@ const char* Abstract_VM_Version::vm_info_string() {
return UseSharedSpaces ? "interpreted mode, sharing" : "interpreted mode";
case Arguments::_mixed:
if (UseSharedSpaces) {
- if (CompilationModeFlag::quick_only()) {
+ if (UseAOT) {
+ return "mixed mode, aot, sharing";
+ } else if (CompilationModeFlag::quick_only()) {
return "mixed mode, emulated-client, sharing";
} else {
return "mixed mode, sharing";
}
} else {
- if (CompilationModeFlag::quick_only()) {
+ if (UseAOT) {
+ return "mixed mode, aot";
+ } else if (CompilationModeFlag::quick_only()) {
return "mixed mode, emulated-client";
} else {
return "mixed mode";
diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp
index a1a737915..406434ab2 100644
--- a/src/hotspot/share/runtime/arguments.cpp
+++ b/src/hotspot/share/runtime/arguments.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -3151,6 +3151,21 @@ jint Arguments::finalize_vm_init_args(bool patch_mod_javabase) {
}
#endif
+#if !INCLUDE_AOT
+ UNSUPPORTED_OPTION(UseAOT);
+ UNSUPPORTED_OPTION(PrintAOT);
+ UNSUPPORTED_OPTION(UseAOTStrictLoading);
+ UNSUPPORTED_OPTION_NULL(AOTLibrary);
+
+ UNSUPPORTED_OPTION_INIT(Tier3AOTInvocationThreshold, 0);
+ UNSUPPORTED_OPTION_INIT(Tier3AOTMinInvocationThreshold, 0);
+ UNSUPPORTED_OPTION_INIT(Tier3AOTCompileThreshold, 0);
+ UNSUPPORTED_OPTION_INIT(Tier3AOTBackEdgeThreshold, 0);
+#ifndef PRODUCT
+ UNSUPPORTED_OPTION(PrintAOTStatistics);
+#endif
+#endif
+
#ifndef CAN_SHOW_REGISTERS_ON_ASSERT
UNSUPPORTED_OPTION(ShowRegistersOnAssert);
#endif // CAN_SHOW_REGISTERS_ON_ASSERT
diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp
index 46a90b678..29e9955a1 100644
--- a/src/hotspot/share/runtime/deoptimization.cpp
+++ b/src/hotspot/share/runtime/deoptimization.cpp
@@ -947,7 +947,7 @@ void Deoptimization::deoptimize_all_marked(nmethod* nmethod_only) {
Deoptimization::DeoptAction Deoptimization::_unloaded_action
= Deoptimization::Action_reinterpret;
-#if COMPILER2_OR_JVMCI
+#if COMPILER2_OR_JVMCI || INCLUDE_AOT
template<typename CacheType>
class BoxCacheBase : public CHeapObj<mtCompiler> {
protected:
@@ -1075,7 +1075,9 @@ oop Deoptimization::get_cached_box(AutoBoxObjectValue* bv, frame* fr, RegisterMa
}
return NULL;
}
+#endif // COMPILER2_OR_JVMCI || INCLUDE_AOT
+#if COMPILER2_OR_JVMCI
bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, TRAPS) {
Handle pending_exception(THREAD, thread->pending_exception());
const char* exception_file = thread->exception_file();
@@ -1092,6 +1094,7 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap*
oop obj = NULL;
if (k->is_instance_klass()) {
+#if COMPILER2_OR_JVMCI || INCLUDE_AOT
if (sv->is_auto_box()) {
AutoBoxObjectValue* abv = (AutoBoxObjectValue*) sv;
obj = get_cached_box(abv, fr, reg_map, THREAD);
@@ -1100,7 +1103,7 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap*
abv->set_cached(true);
}
}
-
+#endif // COMPILER2_OR_JVMCI || INCLUDE_AOT
InstanceKlass* ik = InstanceKlass::cast(k);
if (obj == NULL) {
#ifdef COMPILER2
@@ -1442,11 +1445,12 @@ void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableAr
if (obj.is_null()) {
continue;
}
-
+#if COMPILER2_OR_JVMCI || INCLUDE_AOT
// Don't reassign fields of boxes that came from a cache. Caches may be in CDS.
if (sv->is_auto_box() && ((AutoBoxObjectValue*) sv)->is_cached()) {
continue;
}
+#endif // COMPILER2_OR_JVMCI || INCLUDE_AOT
#ifdef COMPILER2
if (EnableVectorSupport && VectorSupport::is_vector(k)) {
assert(sv->field_size() == 1, "%s not a vector", k->name()->as_C_string());
@@ -1997,7 +2001,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* current, jint tr
int trap_bci = trap_scope->bci();
#if INCLUDE_JVMCI
jlong speculation = current->pending_failed_speculation();
- if (nm->is_compiled_by_jvmci()) {
+ if (nm->is_compiled_by_jvmci() && nm->is_nmethod()) { // Exclude AOTed methods
nm->as_nmethod()->update_speculation(current);
} else {
assert(speculation == 0, "There should not be a speculation for methods compiled by non-JVMCI compilers");
diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp
index 46dde1569..4ed026879 100644
--- a/src/hotspot/share/runtime/frame.cpp
+++ b/src/hotspot/share/runtime/frame.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -577,6 +577,7 @@ void frame::print_C_frame(outputStream* st, char* buf, int buflen, address pc) {
//
// First letter indicates type of the frame:
// J: Java frame (compiled)
+// A: Java frame (aot compiled)
// j: Java frame (interpreted)
// V: VM frame (C/C++)
// v: Other frames running VM generated code (e.g. stubs, adapters, etc.)
@@ -618,7 +619,9 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose
CompiledMethod* cm = (CompiledMethod*)_cb;
Method* m = cm->method();
if (m != NULL) {
- if (cm->is_nmethod()) {
+ if (cm->is_aot()) {
+ st->print("A %d ", cm->compile_id());
+ } else if (cm->is_nmethod()) {
nmethod* nm = cm->as_nmethod();
st->print("J %d%s", nm->compile_id(), (nm->is_osr_method() ? "%" : ""));
st->print(" %s", nm->compiler_name());
@@ -1219,8 +1222,9 @@ void frame::describe(FrameValues& values, int frame_no) {
// For now just label the frame
CompiledMethod* cm = (CompiledMethod*)cb();
values.describe(-1, info_address,
- FormatBuffer<1024>("#%d nmethod " INTPTR_FORMAT " for method J %s%s", frame_no,
+ FormatBuffer<1024>("#%d nmethod " INTPTR_FORMAT " for method %s%s%s", frame_no,
p2i(cm),
+ (cm->is_aot() ? "A ": "J "),
cm->method()->name_and_sig_as_C_string(),
(_deopt_state == is_deoptimized) ?
" (deoptimized)" :
diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp
index 8eae5e5cc..27695a3f5 100644
--- a/src/hotspot/share/runtime/globals.hpp
+++ b/src/hotspot/share/runtime/globals.hpp
@@ -1652,6 +1652,25 @@ const intx ObjectAlignmentInBytes = 8;
"Non-segmented code cache: X[%] of the total code cache") \
range(0, 100) \
\
+ /* AOT parameters */ \
+ product(bool, UseAOT, false, EXPERIMENTAL, \
+ "Use AOT compiled files") \
+ \
+ product(ccstrlist, AOTLibrary, NULL, EXPERIMENTAL, \
+ "AOT library") \
+ \
+ product(bool, PrintAOT, false, EXPERIMENTAL, \
+ "Print used AOT klasses and methods") \
+ \
+ notproduct(bool, PrintAOTStatistics, false, \
+ "Print AOT statistics") \
+ \
+ product(bool, UseAOTStrictLoading, false, DIAGNOSTIC, \
+ "Exit the VM if any of the AOT libraries has invalid config") \
+ \
+ product(bool, CalculateClassFingerprint, false, \
+ "Calculate class fingerprint") \
+ \
/* interpreter debugging */ \
develop(intx, BinarySwitchThreshold, 5, \
"Minimal number of lookupswitch entries for rewriting to binary " \
diff --git a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp
index 06974b89e..09e4313cb 100644
--- a/src/hotspot/share/runtime/init.cpp
+++ b/src/hotspot/share/runtime/init.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -67,6 +67,9 @@ void classLoader_init1();
void compilationPolicy_init();
void codeCache_init();
void VM_Version_init();
+#if INCLUDE_AOT
+void AOTLoader_init();
+#endif
void stubRoutines_init1();
jint universe_init(); // depends on codeCache_init and stubRoutines_init
// depends on universe_init, must be before interpreter_init (currently only on SPARC)
@@ -118,6 +121,9 @@ jint init_globals() {
compilationPolicy_init();
codeCache_init();
VM_Version_init(); // depends on codeCache_init for emitting code
+#if INCLUDE_AOT
+ AOTLoader_init(); // depends on VM_Version_init to adjust vm options
+#endif
stubRoutines_init1();
jint status = universe_init(); // dependent on codeCache_init and
// stubRoutines_init1 and metaspace_init.
diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp
index d7b1c5ed6..e27a135fc 100644
--- a/src/hotspot/share/runtime/java.cpp
+++ b/src/hotspot/share/runtime/java.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -96,6 +96,9 @@
#if INCLUDE_JBOOSTER
#include "jbooster/client/clientMessageHandler.hpp"
#endif // INCLUDE_JBOOSTER
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
GrowableArray<Method*>* collected_profiled_methods;
@@ -270,6 +273,12 @@ void print_statistics() {
#endif // INCLUDE_JVMCI
#endif // COMPILER2
+#if INCLUDE_AOT
+ if (PrintAOTStatistics) {
+ AOTLoader::print_statistics();
+ }
+#endif
+
if (PrintNMethodStatistics) {
nmethod::print_statistics();
}
diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp
index 9af4b513a..bb6ff23e4 100644
--- a/src/hotspot/share/runtime/sharedRuntime.cpp
+++ b/src/hotspot/share/runtime/sharedRuntime.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -79,6 +79,9 @@
#ifdef COMPILER1
#include "c1/c1_Runtime1.hpp"
#endif
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
// Shared stub locations
RuntimeStub* SharedRuntime::_wrong_method_blob;
@@ -1327,8 +1330,8 @@ bool SharedRuntime::resolve_sub_helper_internal(methodHandle callee_method, cons
if (VM_Version::supports_fast_class_init_checks() &&
invoke_code == Bytecodes::_invokestatic &&
callee_method->needs_clinit_barrier() &&
- callee != NULL && callee->is_compiled_by_jvmci()) {
- return true; // skip patching for JVMCI
+ callee != NULL && (callee->is_compiled_by_jvmci() || callee->is_aot())) {
+ return true; // skip patching for JVMCI or AOT code
}
CompiledStaticCall* ssc = caller_nm->compiledStaticCall_before(caller_frame.pc());
if (ssc->is_clean()) ssc->set(static_call_info);
diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp
index c057b1ef5..a5d5d1ec7 100644
--- a/src/hotspot/share/runtime/thread.cpp
+++ b/src/hotspot/share/runtime/thread.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2021, Azul Systems, Inc. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2023, Azul Systems, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -152,6 +152,9 @@
#if INCLUDE_JBOOSTER
#include "jbooster/jBoosterManager.hpp"
#endif // INCLUDE_JBOOSTER
+#if INCLUDE_AOT
+#include "aot/aotLoader.hpp"
+#endif
// Initialization after module runtime initialization
void universe_post_module_init(); // must happen after call_initPhase2
@@ -2744,6 +2747,10 @@ void Threads::initialize_java_lang_classes(JavaThread* main_thread, TRAPS) {
initialize_class(vmSymbols::java_lang_StackOverflowError(), CHECK);
initialize_class(vmSymbols::java_lang_IllegalMonitorStateException(), CHECK);
initialize_class(vmSymbols::java_lang_IllegalArgumentException(), CHECK);
+#if INCLUDE_AOT
+ // Eager box cache initialization only if AOT is on and any library is loaded.
+ AOTLoader::initialize_box_caches(CHECK);
+#endif
}
void Threads::initialize_jsr292_core_classes(TRAPS) {
@@ -2955,8 +2962,8 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
}
// We need this to update the java.vm.info property in case any flags used
- // to initially define it have been changed. This is needed for both CDS
- // since UseSharedSpaces may be changed after java.vm.info
+ // to initially define it have been changed. This is needed for both CDS and
+ // AOT, since UseSharedSpaces and UseAOT may be changed after java.vm.info
// is initially computed. See Abstract_VM_Version::vm_info_string().
// This update must happen before we initialize the java classes, but
// after any initialization logic that might modify the flags.
diff --git a/src/hotspot/share/runtime/vframe_hp.cpp b/src/hotspot/share/runtime/vframe_hp.cpp
index 8405bb540..b6c919a38 100644
--- a/src/hotspot/share/runtime/vframe_hp.cpp
+++ b/src/hotspot/share/runtime/vframe_hp.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -228,7 +228,7 @@ GrowableArray<MonitorInfo*>* compiledVFrame::monitors() const {
if (scope() == NULL) {
CompiledMethod* nm = code();
Method* method = nm->method();
- assert(method->is_native(), "Expect a native method");
+ assert(method->is_native() || nm->is_aot(), "Expect a native method or precompiled method");
if (!method->is_synchronized()) {
return new GrowableArray<MonitorInfo*>(0);
}
diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp
index 33de84a68..ef2a366f7 100644
--- a/src/hotspot/share/runtime/vmStructs.cpp
+++ b/src/hotspot/share/runtime/vmStructs.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -300,6 +300,7 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
JVMTI_ONLY(nonstatic_field(MethodCounters, _number_of_breakpoints, u2)) \
nonstatic_field(MethodCounters, _invocation_counter, InvocationCounter) \
nonstatic_field(MethodCounters, _backedge_counter, InvocationCounter) \
+ AOT_ONLY(nonstatic_field(MethodCounters, _method, Method*)) \
nonstatic_field(Method, _constMethod, ConstMethod*) \
nonstatic_field(Method, _method_data, MethodData*) \
nonstatic_field(Method, _method_counters, MethodCounters*) \
@@ -2494,6 +2495,7 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
declare_constant(CompLevel_limited_profile) \
declare_constant(CompLevel_full_profile) \
declare_constant(CompLevel_full_optimization) \
+ declare_constant(CompLevel_aot) \
\
/***************/ \
/* OopMapValue */ \
diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp
index fde84e048..6f8cc606f 100644
--- a/src/hotspot/share/utilities/macros.hpp
+++ b/src/hotspot/share/utilities/macros.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -283,6 +283,14 @@
#define INCLUDE_JVMCI 1
#endif
+#ifndef INCLUDE_AOT
+#define INCLUDE_AOT 1
+#endif
+
+#if INCLUDE_AOT && !INCLUDE_JVMCI
+# error "Must have JVMCI for AOT"
+#endif
+
#if INCLUDE_JVMCI
#define JVMCI_ONLY(code) code
#define NOT_JVMCI(code)
@@ -293,6 +301,16 @@
#define NOT_JVMCI_RETURN {}
#endif // INCLUDE_JVMCI
+#if INCLUDE_AOT
+#define AOT_ONLY(code) code
+#define NOT_AOT(code)
+#define NOT_AOT_RETURN /* next token must be ; */
+#else
+#define AOT_ONLY(code)
+#define NOT_AOT(code) code
+#define NOT_AOT_RETURN {}
+#endif // INCLUDE_AOT
+
// COMPILER1 variant
#ifdef COMPILER1
#define COMPILER1_PRESENT(code) code
diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp
index 2f4a489e3..9f3690cdc 100644
--- a/src/hotspot/share/utilities/vmError.cpp
+++ b/src/hotspot/share/utilities/vmError.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2017, 2020 SAP SE. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2023 SAP SE. All rights reserved.
* Copyright (c) 2023, Red Hat, Inc. and/or its affiliates.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -371,7 +371,7 @@ void VMError::print_native_stack(outputStream* st, frame fr, Thread* t, char* bu
// see if it's a valid frame
if (fr.pc()) {
- st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)");
+ st->print_cr("Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code)");
int count = 0;
while (count++ < StackPrintLimit) {
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java
new file mode 100644
index 000000000..b39bc4069
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java
@@ -0,0 +1,959 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat;
+
+import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
+
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+import jdk.tools.jaotc.binformat.elf.JELFRelocObject;
+import jdk.tools.jaotc.binformat.macho.JMachORelocObject;
+import jdk.tools.jaotc.binformat.pecoff.JPECoffRelocObject;
+
+/**
+ * A format-agnostic container class that holds various components of a binary.
+ *
+ * <p>
+ * This class holds information necessary to create platform-specific binary containers such as
+ * ELFContainer for Linux or MachOContainer for Mac OS or PEContainer for MS Windows operating
+ * systems.
+ *
+ * <p>
+ * Method APIs provided by this class are used to construct and populate platform-independent
+ * contents of a binary as the first step to create a binary representation of code generated by a
+ * compiler backend such as Graal.
+ *
+ * <p>
+ * Methods to record and access code section contents, symbols and relocations are provided.
+ */
+public final class BinaryContainer implements SymbolTable {
+ private final OptionValues graalOptions;
+
+ private final int codeSegmentSize;
+
+ private final int codeEntryAlignment;
+
+ private final boolean threadLocalHandshakes;
+
+ /**
+ * Container holding code bits and any other related information.
+ */
+ private final CodeContainer codeContainer;
+
+ /**
+ * Container holding global offset data for hotspot linkage.
+ */
+ private final ByteContainer extLinkageGOTContainer;
+
+ /**
+ * Patched by HotSpot, contains Klass pointers.
+ */
+ private final ByteContainer klassesGotContainer;
+
+ /**
+ * Patched by HotSpot, contains MethodCounters pointers.
+ */
+ private final ByteContainer countersGotContainer;
+
+ /**
+ * Patched lazily by hotspot, contains klass/method pointers.
+ */
+ private final ByteContainer metadataGotContainer;
+
+ /**
+ * BSS container, contains method state array.
+ */
+ private final ByteContainer methodStateContainer;
+
+ /**
+ * Patched by hotspot, contains java object pointers.
+ */
+ private final ByteContainer oopGotContainer;
+
+ // Containers holding read-only data
+ private final ReadOnlyDataContainer configContainer;
+ private final ReadOnlyDataContainer metaspaceNamesContainer;
+ private final ReadOnlyDataContainer methodsOffsetsContainer;
+ private final ReadOnlyDataContainer klassesOffsetsContainer;
+ private final ReadOnlyDataContainer klassesDependenciesContainer;
+ private final HeaderContainer headerContainer;
+ private final ReadOnlyDataContainer stubsOffsetsContainer;
+ private final ReadOnlyDataContainer codeSegmentsContainer;
+
+ // This cannot be read only since we need to patch the metadata at runtime..
+ private final ReadOnlyDataContainer methodMetadataContainer;
+
+ /**
+ * Container containing constant data used by code.
+ */
+ private final ReadOnlyDataContainer constantDataContainer;
+
+ /**
+ * Map holding the Strings table.
+ */
+ private final Map<String, Integer> offsetStringTable = new HashMap<>();
+
+ private final Map<String, Integer> metaspaceNames = new HashMap<>();
+
+ // List of relocation table entries - (symbolName, relocationInfo)
+ private final Map<String, Symbol> symbolTable = new HashMap<>();
+ private final Map<Symbol, List<Relocation>> relocationTable = new HashMap<>();
+ private final Map<Symbol, Relocation> uniqueRelocationTable = new HashMap<>();
+
+ /**
+ * Mapping of local VM function names to known global symbols generated in the output binary.
+ */
+ private static final HashMap<String, String> functionNamesToAOTSymbols = new HashMap<>();
+
+ //@formatter:off
+ private static final String[][] map = {
+ {"CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", "_aot_deopt_blob_unpack"},
+ {"CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap", "_aot_deopt_blob_uncommon_trap"},
+ {"CompilerToVM::Data::SharedRuntime_deopt_blob_unpack_with_exception_in_tls", "_aot_deopt_blob_unpack_with_exception_in_tls"},
+ {"CompilerToVM::Data::SharedRuntime_ic_miss_stub", "_aot_ic_miss_stub"},
+ {"CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub", "_aot_handle_wrong_method_stub"},
+ {"SharedRuntime::exception_handler_for_return_address", "_aot_exception_handler_for_return_address"},
+ {"SharedRuntime::register_finalizer", "_aot_register_finalizer"},
+ {"SharedRuntime::OSR_migration_end", "_aot_OSR_migration_end"},
+ {"SharedRuntime::enable_stack_reserved_zone", "_aot_enable_stack_reserved_zone"},
+ {"CompilerRuntime::resolve_dynamic_invoke", "_aot_resolve_dynamic_invoke"},
+ {"CompilerRuntime::resolve_string_by_symbol", "_aot_resolve_string_by_symbol"},
+ {"CompilerRuntime::resolve_klass_by_symbol", "_aot_resolve_klass_by_symbol"},
+ {"CompilerRuntime::resolve_method_by_symbol_and_load_counters", "_aot_resolve_method_by_symbol_and_load_counters"},
+ {"CompilerRuntime::initialize_klass_by_symbol", "_aot_initialize_klass_by_symbol"},
+ {"CompilerRuntime::invocation_event", "_aot_invocation_event"},
+ {"CompilerRuntime::backedge_event", "_aot_backedge_event"},
+
+ {"CompilerToVM::Data::dpow", "_aot_shared_runtime_dpow"},
+ {"CompilerToVM::Data::dexp", "_aot_shared_runtime_dexp"},
+ {"CompilerToVM::Data::dcos", "_aot_shared_runtime_dcos"},
+ {"CompilerToVM::Data::dsin", "_aot_shared_runtime_dsin"},
+ {"CompilerToVM::Data::dtan", "_aot_shared_runtime_dtan"},
+ {"CompilerToVM::Data::dlog", "_aot_shared_runtime_dlog"},
+ {"CompilerToVM::Data::dlog10", "_aot_shared_runtime_dlog10"},
+
+ {"StubRoutines::_jbyte_arraycopy", "_aot_stub_routines_jbyte_arraycopy"},
+ {"StubRoutines::_jshort_arraycopy", "_aot_stub_routines_jshort_arraycopy"},
+ {"StubRoutines::_jint_arraycopy", "_aot_stub_routines_jint_arraycopy"},
+ {"StubRoutines::_jlong_arraycopy", "_aot_stub_routines_jlong_arraycopy"},
+ {"StubRoutines::_oop_arraycopy", "_aot_stub_routines_oop_arraycopy"},
+ {"StubRoutines::_oop_arraycopy_uninit", "_aot_stub_routines_oop_arraycopy_uninit"},
+
+ {"StubRoutines::_jbyte_disjoint_arraycopy", "_aot_stub_routines_jbyte_disjoint_arraycopy"},
+ {"StubRoutines::_jshort_disjoint_arraycopy", "_aot_stub_routines_jshort_disjoint_arraycopy"},
+ {"StubRoutines::_jint_disjoint_arraycopy", "_aot_stub_routines_jint_disjoint_arraycopy"},
+ {"StubRoutines::_jlong_disjoint_arraycopy", "_aot_stub_routines_jlong_disjoint_arraycopy"},
+ {"StubRoutines::_oop_disjoint_arraycopy", "_aot_stub_routines_oop_disjoint_arraycopy"},
+ {"StubRoutines::_oop_disjoint_arraycopy_uninit", "_aot_stub_routines_oop_disjoint_arraycopy_uninit"},
+
+ {"StubRoutines::_arrayof_jbyte_arraycopy", "_aot_stub_routines_arrayof_jbyte_arraycopy"},
+ {"StubRoutines::_arrayof_jshort_arraycopy", "_aot_stub_routines_arrayof_jshort_arraycopy"},
+ {"StubRoutines::_arrayof_jint_arraycopy", "_aot_stub_routines_arrayof_jint_arraycopy"},
+ {"StubRoutines::_arrayof_jlong_arraycopy", "_aot_stub_routines_arrayof_jlong_arraycopy"},
+ {"StubRoutines::_arrayof_oop_arraycopy", "_aot_stub_routines_arrayof_oop_arraycopy"},
+ {"StubRoutines::_arrayof_oop_arraycopy_uninit", "_aot_stub_routines_arrayof_oop_arraycopy_uninit"},
+
+ {"StubRoutines::_arrayof_jbyte_disjoint_arraycopy", "_aot_stub_routines_arrayof_jbyte_disjoint_arraycopy"},
+ {"StubRoutines::_arrayof_jshort_disjoint_arraycopy", "_aot_stub_routines_arrayof_jshort_disjoint_arraycopy"},
+ {"StubRoutines::_arrayof_jint_disjoint_arraycopy", "_aot_stub_routines_arrayof_jint_disjoint_arraycopy"},
+ {"StubRoutines::_arrayof_jlong_disjoint_arraycopy", "_aot_stub_routines_arrayof_jlong_disjoint_arraycopy"},
+ {"StubRoutines::_arrayof_oop_disjoint_arraycopy", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy"},
+ {"StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit"},
+
+ {"StubRoutines::_unsafe_arraycopy", "_aot_stub_routines_unsafe_arraycopy"},
+
+ {"StubRoutines::_checkcast_arraycopy", "_aot_stub_routines_checkcast_arraycopy"},
+
+ {"StubRoutines::_generic_arraycopy", "_aot_stub_routines_generic_arraycopy"},
+
+ {"StubRoutines::_aescrypt_encryptBlock", "_aot_stub_routines_aescrypt_encryptBlock"},
+ {"StubRoutines::_aescrypt_decryptBlock", "_aot_stub_routines_aescrypt_decryptBlock"},
+ {"StubRoutines::_cipherBlockChaining_encryptAESCrypt", "_aot_stub_routines_cipherBlockChaining_encryptAESCrypt"},
+ {"StubRoutines::_cipherBlockChaining_decryptAESCrypt", "_aot_stub_routines_cipherBlockChaining_decryptAESCrypt"},
+ {"StubRoutines::_electronicCodeBook_encryptAESCrypt", "_aot_stub_routines_electronicCodeBook_encryptAESCrypt"},
+ {"StubRoutines::_electronicCodeBook_decryptAESCrypt", "_aot_stub_routines_electronicCodeBook_decryptAESCrypt"},
+ {"StubRoutines::_updateBytesCRC32", "_aot_stub_routines_update_bytes_crc32"},
+ {"StubRoutines::_crc_table_adr", "_aot_stub_routines_crc_table_adr"},
+
+ {"StubRoutines::_sha1_implCompress", "_aot_stub_routines_sha1_implCompress" },
+ {"StubRoutines::_sha1_implCompressMB", "_aot_stub_routines_sha1_implCompressMB" },
+ {"StubRoutines::_sha256_implCompress", "_aot_stub_routines_sha256_implCompress" },
+ {"StubRoutines::_sha256_implCompressMB", "_aot_stub_routines_sha256_implCompressMB" },
+ {"StubRoutines::_sha512_implCompress", "_aot_stub_routines_sha512_implCompress" },
+ {"StubRoutines::_sha512_implCompressMB", "_aot_stub_routines_sha512_implCompressMB" },
+ {"StubRoutines::_multiplyToLen", "_aot_stub_routines_multiplyToLen" },
+
+ {"StubRoutines::_counterMode_AESCrypt", "_aot_stub_routines_counterMode_AESCrypt" },
+ {"StubRoutines::_ghash_processBlocks", "_aot_stub_routines_ghash_processBlocks" },
+ {"StubRoutines::_base64_encodeBlock", "_aot_stub_routines_base64_encodeBlock" },
+ {"StubRoutines::_crc32c_table_addr", "_aot_stub_routines_crc32c_table_addr" },
+ {"StubRoutines::_updateBytesCRC32C", "_aot_stub_routines_updateBytesCRC32C" },
+ {"StubRoutines::_updateBytesAdler32", "_aot_stub_routines_updateBytesAdler32" },
+ {"StubRoutines::_squareToLen", "_aot_stub_routines_squareToLen" },
+ {"StubRoutines::_mulAdd", "_aot_stub_routines_mulAdd" },
+ {"StubRoutines::_montgomeryMultiply", "_aot_stub_routines_montgomeryMultiply" },
+ {"StubRoutines::_montgomerySquare", "_aot_stub_routines_montgomerySquare" },
+ {"StubRoutines::_vectorizedMismatch", "_aot_stub_routines_vectorizedMismatch" },
+ {"StubRoutines::_bigIntegerRightShiftWorker", "_aot_stub_routines_bigIntegerRightShiftWorker" },
+ {"StubRoutines::_bigIntegerLeftShiftWorker", "_aot_stub_routines_bigIntegerLeftShiftWorker" },
+
+ {"StubRoutines::_throw_delayed_StackOverflowError_entry", "_aot_stub_routines_throw_delayed_StackOverflowError_entry" },
+
+
+ {"os::javaTimeMillis", "_aot_os_javaTimeMillis"},
+ {"os::javaTimeNanos", "_aot_os_javaTimeNanos"},
+
+ {"JVMCIRuntime::monitorenter", "_aot_jvmci_runtime_monitorenter"},
+ {"JVMCIRuntime::monitorexit", "_aot_jvmci_runtime_monitorexit"},
+ {"JVMCIRuntime::object_notify", "_aot_object_notify"},
+ {"JVMCIRuntime::object_notifyAll", "_aot_object_notifyAll"},
+ {"JVMCIRuntime::log_object", "_aot_jvmci_runtime_log_object"},
+ {"JVMCIRuntime::log_printf", "_aot_jvmci_runtime_log_printf"},
+ {"JVMCIRuntime::vm_message", "_aot_jvmci_runtime_vm_message"},
+ {"JVMCIRuntime::new_instance", "_aot_jvmci_runtime_new_instance"},
+ {"JVMCIRuntime::new_array", "_aot_jvmci_runtime_new_array"},
+ {"JVMCIRuntime::new_multi_array", "_aot_jvmci_runtime_new_multi_array"},
+ {"JVMCIRuntime::dynamic_new_instance", "_aot_jvmci_runtime_dynamic_new_instance"},
+ {"JVMCIRuntime::dynamic_new_array", "_aot_jvmci_runtime_dynamic_new_array"},
+ {"JVMCIRuntime::new_instance_or_null", "_aot_jvmci_runtime_new_instance_or_null"},
+ {"JVMCIRuntime::new_array_or_null", "_aot_jvmci_runtime_new_array_or_null"},
+ {"JVMCIRuntime::new_multi_array_or_null", "_aot_jvmci_runtime_new_multi_array_or_null"},
+ {"JVMCIRuntime::dynamic_new_instance_or_null", "_aot_jvmci_runtime_dynamic_new_instance_or_null"},
+ {"JVMCIRuntime::dynamic_new_array_or_null", "_aot_jvmci_runtime_dynamic_new_array_or_null"},
+ {"JVMCIRuntime::log_primitive", "_aot_jvmci_runtime_log_primitive"},
+ {"JVMCIRuntime::validate_object", "_aot_jvmci_runtime_validate_object"},
+ {"JVMCIRuntime::write_barrier_pre", "_aot_jvmci_runtime_write_barrier_pre"},
+ {"JVMCIRuntime::identity_hash_code", "_aot_jvmci_runtime_identity_hash_code"},
+ {"JVMCIRuntime::write_barrier_post", "_aot_jvmci_runtime_write_barrier_post"},
+ {"JVMCIRuntime::thread_is_interrupted", "_aot_jvmci_runtime_thread_is_interrupted"},
+ {"JVMCIRuntime::exception_handler_for_pc", "_aot_jvmci_runtime_exception_handler_for_pc"},
+ {"JVMCIRuntime::test_deoptimize_call_int", "_aot_jvmci_runtime_test_deoptimize_call_int"},
+
+ {"JVMCIRuntime::throw_and_post_jvmti_exception", "_aot_jvmci_runtime_throw_and_post_jvmti_exception"},
+ {"JVMCIRuntime::throw_klass_external_name_exception", "_aot_jvmci_runtime_throw_klass_external_name_exception"},
+ {"JVMCIRuntime::throw_class_cast_exception", "_aot_jvmci_runtime_throw_class_cast_exception"},
+
+ {"JVMCIRuntime::vm_error", "_aot_jvmci_runtime_vm_error"}
+ };
+ //@formatter:on
+
+ static {
+ for (String[] entry : map) {
+ functionNamesToAOTSymbols.put(entry[0], entry[1]);
+ }
+ }
+
+ /**
+ * Allocates a {@code BinaryContainer} object whose content will be generated in a file with the
+ * prefix {@code prefix}. It also initializes internal code container, symbol table and
+ * relocation tables.
+ *
+ * @param graalOptions
+ */
+ public BinaryContainer(OptionValues graalOptions, GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, int gc, String jvmVersion) {
+ this.graalOptions = graalOptions;
+
+ this.codeSegmentSize = graalHotSpotVMConfig.codeSegmentSize;
+ if (codeSegmentSize < 1 || codeSegmentSize > 1024) {
+ throw new InternalError("codeSegmentSize is not in range [1, 1024] bytes: (" + codeSegmentSize + "), update JPECoffRelocObject");
+ }
+ if ((codeSegmentSize & (codeSegmentSize - 1)) != 0) {
+ throw new InternalError("codeSegmentSize is not power of 2: (" + codeSegmentSize + "), update JPECoffRelocObject");
+ }
+
+ this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment;
+
+ this.threadLocalHandshakes = graalHotSpotVMConfig.useThreadLocalPolling;
+
+ // Section unique name is limited to 8 characters due to limitation on Windows.
+ // Name could be longer but only first 8 characters are stored on Windows.
+
+ // read only, code
+ codeContainer = new CodeContainer(".text", this);
+
+ // read only, info
+ headerContainer = new HeaderContainer(jvmVersion, new ReadOnlyDataContainer(".header", this));
+ configContainer = new ReadOnlyDataContainer(".config", this);
+ metaspaceNamesContainer = new ReadOnlyDataContainer(".meta.names", this);
+ methodsOffsetsContainer = new ReadOnlyDataContainer(".meth.offsets", this);
+ klassesOffsetsContainer = new ReadOnlyDataContainer(".kls.offsets", this);
+ klassesDependenciesContainer = new ReadOnlyDataContainer(".kls.dependencies", this);
+
+ stubsOffsetsContainer = new ReadOnlyDataContainer(".stubs.offsets", this);
+ codeSegmentsContainer = new ReadOnlyDataContainer(".code.segments", this);
+ constantDataContainer = new ReadOnlyDataContainer(".meth.constdata", this);
+ methodMetadataContainer = new ReadOnlyDataContainer(".meth.metadata", this);
+
+ // writable sections
+ oopGotContainer = new ByteContainer(".oop.got", this);
+ klassesGotContainer = new ByteContainer(".kls.got", this);
+ countersGotContainer = new ByteContainer(".cnt.got", this);
+ metadataGotContainer = new ByteContainer(".meta.got", this);
+ methodStateContainer = new ByteContainer(".meth.state", this);
+ extLinkageGOTContainer = new ByteContainer(".got.linkage", this);
+
+ addGlobalSymbols();
+
+ recordConfiguration(graalHotSpotVMConfig, graphBuilderConfig, gc);
+ }
+
+ private void recordConfiguration(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, int gc) {
+ // @Checkstyle: stop
+ // @formatter:off
+ ArrayList<Boolean> booleanFlagsList = new ArrayList<>();
+
+ booleanFlagsList.addAll(Arrays.asList(graalHotSpotVMConfig.cAssertions, // Debug VM
+ graalHotSpotVMConfig.useCompressedOops,
+ graalHotSpotVMConfig.useCompressedClassPointers));
+ if (JavaVersionUtil.JAVA_SPEC < 15) {
+ // See JDK-8236224. FieldsAllocationStyle and CompactFields flags were removed in JDK15.
+ booleanFlagsList.add(graalHotSpotVMConfig.compactFields);
+ }
+ booleanFlagsList.addAll(Arrays.asList(graalHotSpotVMConfig.useTLAB,
+ graalHotSpotVMConfig.useBiasedLocking,
+ TieredAOT.getValue(graalOptions),
+ graalHotSpotVMConfig.enableContended,
+ graalHotSpotVMConfig.restrictContended,
+ graphBuilderConfig.omitAssertions()));
+ if (JavaVersionUtil.JAVA_SPEC < 14) {
+ // See JDK-8220049. Thread local handshakes are on by default since JDK14, the command line option has been removed.
+ booleanFlagsList.add(graalHotSpotVMConfig.useThreadLocalPolling);
+ }
+
+ ArrayList<Integer> intFlagsList = new ArrayList<>();
+ intFlagsList.addAll(Arrays.asList(graalHotSpotVMConfig.getOopEncoding().getShift(),
+ graalHotSpotVMConfig.getKlassEncoding().getShift(),
+ graalHotSpotVMConfig.contendedPaddingWidth));
+ if (JavaVersionUtil.JAVA_SPEC < 15) {
+ // See JDK-8236224. FieldsAllocationStyle and CompactFields flags were removed in JDK15.
+ intFlagsList.add(graalHotSpotVMConfig.fieldsAllocationStyle);
+ }
+ intFlagsList.addAll(Arrays.asList(1 << graalHotSpotVMConfig.logMinObjAlignment(),
+ graalHotSpotVMConfig.codeSegmentSize,
+ gc));
+
+ // @formatter:on
+ // @Checkstyle: resume
+
+ byte[] booleanFlagsAsBytes = booleanListToByteArray(booleanFlagsList);
+ int[] intFlags = intFlagsList.stream().mapToInt(i -> i).toArray();
+ int size0 = configContainer.getByteStreamSize();
+
+ // @formatter:off
+ int computedSize = booleanFlagsAsBytes.length * Byte.BYTES + // size of boolean flags
+ intFlags.length * Integer.BYTES + // size of int flags
+ Integer.BYTES; // size of the "computedSize"
+
+ configContainer.appendInt(computedSize).
+ appendInts(intFlags).
+ appendBytes(booleanFlagsAsBytes);
+ // @formatter:on
+
+ int size = configContainer.getByteStreamSize() - size0;
+ assert size == computedSize;
+ }
+
+ private static byte[] booleanListToByteArray(ArrayList<Boolean> list) {
+ byte[] byteArray = new byte[list.size()];
+ for (int i = 0; i < list.size(); ++i) {
+ byteArray[i] = boolToByte(list.get(i));
+ }
+ return byteArray;
+ }
+
+ private static byte boolToByte(boolean flag) {
+ return (byte) (flag ? 1 : 0);
+ }
+
+ /**
+ * Free some memory.
+ */
+ public void freeMemory() {
+ offsetStringTable.clear();
+ metaspaceNames.clear();
+ }
+
+ /*
+ * Global symbol names in generated DSO corresponding to VM's symbols. VM needs to look up this
+ * symbol in DSO and link it with VM's corresponding symbol: store VM's symbol address or value
+ * in the named GOT cell.
+ */
+
+ public static String getCardTableAddressSymbolName() {
+ return "_aot_card_table_address";
+ }
+
+ public static String getHeapTopAddressSymbolName() {
+ return "_aot_heap_top_address";
+ }
+
+ public static String getHeapEndAddressSymbolName() {
+ return "_aot_heap_end_address";
+ }
+
+ public static String getCrcTableAddressSymbolName() {
+ return "_aot_stub_routines_crc_table_adr";
+ }
+
+ public static String getPollingPageSymbolName() {
+ return "_aot_polling_page";
+ }
+
+ public static String getResolveStaticEntrySymbolName() {
+ return "_resolve_static_entry";
+ }
+
+ public static String getResolveVirtualEntrySymbolName() {
+ return "_resolve_virtual_entry";
+ }
+
+ public static String getResolveOptVirtualEntrySymbolName() {
+ return "_resolve_opt_virtual_entry";
+ }
+
+ public static String getNarrowKlassBaseAddressSymbolName() {
+ return "_aot_narrow_klass_base_address";
+ }
+
+ public static String getNarrowOopBaseAddressSymbolName() {
+ return "_aot_narrow_oop_base_address";
+ }
+
+ public static String getLogOfHeapRegionGrainBytesSymbolName() {
+ return "_aot_log_of_heap_region_grain_bytes";
+ }
+
+ public static String getInlineContiguousAllocationSupportedSymbolName() {
+ return "_aot_inline_contiguous_allocation_supported";
+ }
+
+ public static String getVerifyOopsSymbolName() {
+ return "_aot_verify_oops";
+ }
+
+ public static String getVerifyOopCountAddressSymbolName() {
+ return "_aot_verify_oop_count_address";
+ }
+
+ public static String getVerifyOopBitsSymbolName() {
+ return "_aot_verify_oop_bits";
+ }
+
+ public static String getVerifyOopMaskSymbolName() {
+ return "_aot_verify_oop_mask";
+ }
+
+ public int getCodeSegmentSize() {
+ return codeSegmentSize;
+ }
+
+ public int getCodeEntryAlignment() {
+ return codeEntryAlignment;
+ }
+
+ public boolean getThreadLocalHandshakes() {
+ return threadLocalHandshakes;
+ }
+
+ /**
+ * Gets the global AOT symbol associated with the function name.
+ *
+ * @param functionName function name
+ * @return AOT symbol for the given function name, or null if there is no mapping.
+ */
+ public static String getAOTSymbolForVMFunctionName(String functionName) {
+ return functionNamesToAOTSymbols.get(functionName);
+ }
+
+ private void addGlobalSymbols() {
+ // Create global symbols for all containers.
+ createContainerSymbol(codeContainer);
+ createContainerSymbol(configContainer);
+ createContainerSymbol(methodsOffsetsContainer);
+ createContainerSymbol(klassesOffsetsContainer);
+ createContainerSymbol(klassesDependenciesContainer);
+ createContainerSymbol(klassesGotContainer);
+ createContainerSymbol(countersGotContainer);
+ createContainerSymbol(metadataGotContainer);
+ createContainerSymbol(methodStateContainer);
+ createContainerSymbol(oopGotContainer);
+ createContainerSymbol(metaspaceNamesContainer);
+ createContainerSymbol(methodMetadataContainer);
+ createContainerSymbol(stubsOffsetsContainer);
+ createContainerSymbol(headerContainer.getContainer());
+ createContainerSymbol(codeSegmentsContainer);
+
+ createGotSymbol(getResolveStaticEntrySymbolName());
+ createGotSymbol(getResolveVirtualEntrySymbolName());
+ createGotSymbol(getResolveOptVirtualEntrySymbolName());
+ createGotSymbol(getCardTableAddressSymbolName());
+ createGotSymbol(getHeapTopAddressSymbolName());
+ createGotSymbol(getHeapEndAddressSymbolName());
+ createGotSymbol(getNarrowKlassBaseAddressSymbolName());
+ createGotSymbol(getNarrowOopBaseAddressSymbolName());
+ createGotSymbol(getPollingPageSymbolName());
+ createGotSymbol(getLogOfHeapRegionGrainBytesSymbolName());
+ createGotSymbol(getInlineContiguousAllocationSupportedSymbolName());
+ createGotSymbol(getVerifyOopsSymbolName());
+ createGotSymbol(getVerifyOopCountAddressSymbolName());
+ createGotSymbol(getVerifyOopBitsSymbolName());
+ createGotSymbol(getVerifyOopMaskSymbolName());
+
+ for (HashMap.Entry<String, String> entry : functionNamesToAOTSymbols.entrySet()) {
+ createGotSymbol(entry.getValue());
+ }
+ }
+
+ /**
+ * Creates a global symbol of the form {@code "A" + container name}. Note, linker on Windows
+ * does not allow names which start with '.'
+ *
+ * @param container container to create a symbol for
+ */
+ private static void createContainerSymbol(ByteContainer container) {
+ container.createSymbol(0, Kind.OBJECT, Binding.GLOBAL, 0, "A" + container.getContainerName());
+ }
+
+ /**
+ * Creates a global GOT symbol of the form {@code "got." + name}.
+ *
+ * @param name name for the GOT symbol
+ */
+ private void createGotSymbol(String name) {
+ String s = "got." + name;
+ Symbol gotSymbol = extLinkageGOTContainer.createGotSymbol(s);
+ extLinkageGOTContainer.createSymbol(gotSymbol.getOffset(), Kind.OBJECT, Binding.GLOBAL, 8, name);
+ }
+
+ /**
+ * Create a platform-specific binary file representing the content of the
+ * {@code BinaryContainer} object.
+ *
+ * This method is called after creating and performing any necessary changes to the contents of
+ * code stream, symbol tables and relocation tables is completely finalized
+ *
+ * @param outputFileName name of output file
+ *
+ * @throws IOException in case of file creation failure
+ */
+ public void createBinary(String outputFileName) throws IOException {
+ String osName = System.getProperty("os.name");
+ switch (osName) {
+ case "Linux":
+ JELFRelocObject elfobj = JELFRelocObject.newInstance(this, outputFileName);
+ elfobj.createELFRelocObject(relocationTable, symbolTable.values());
+ break;
+ case "Mac OS X":
+ JMachORelocObject machobj = new JMachORelocObject(this, outputFileName);
+ machobj.createMachORelocObject(relocationTable, symbolTable.values());
+ break;
+ default:
+ if (osName.startsWith("Windows")) {
+ JPECoffRelocObject pecoffobj = new JPECoffRelocObject(this, outputFileName);
+ pecoffobj.createPECoffRelocObject(relocationTable, symbolTable.values());
+ break;
+ } else {
+ throw new InternalError("Unsupported platform: " + osName);
+ }
+ }
+ }
+
+ /**
+ * Add symbol to the symbol table. If the existing symbol is undefined and the specified symbol
+ * is not undefined, replace the existing symbol information with that specified.
+ *
+ * @param symInfo symbol information to be added
+ */
+ @Override
+ public void addSymbol(Symbol symInfo) {
+ if (symInfo.getName().startsWith("got.") && !(symInfo instanceof GotSymbol)) {
+ throw new InternalError("adding got. without being GotSymbol");
+ }
+ if (symbolTable.containsKey(symInfo.getName())) {
+ throw new InternalError("Symbol: " + symInfo.getName() + " already exists in SymbolTable");
+ } else {
+ // System.out.println("# Symbol [" + name + "] [" + symInfo.getValue() + "] [" +
+ // symInfo.getSection().getContainerName() + "] [" + symInfo.getSize() + "]");
+ symbolTable.put(symInfo.getName(), symInfo);
+ }
+ }
+
+ public boolean addStringOffset(String name, Integer offset) {
+ offsetStringTable.put(name, offset);
+ return true;
+ }
+
+ /**
+ * Add relocation entry for {@code symName}. Multiple relocation entries for a given symbol may
+ * exist.
+ *
+ * @param info relocation information to be added
+ */
+ public void addRelocation(Relocation info) {
+ // System.out.println("# Relocation [" + info.getSymbol() + "] [" + info.getOffset() + "] ["
+ // +
+ // info.getSection().getContainerName() + "] [" + info.getSymbol().getName() + "] [" +
+ // info.getSymbol().getOffset() + " @ " + info.getSymbol().getSection().getContainerName() +
+ // "]");
+ if (relocationTable.containsKey(info.getSymbol())) {
+ relocationTable.get(info.getSymbol()).add(info);
+ } else if (uniqueRelocationTable.containsKey(info.getSymbol())) {
+ // promote
+ ArrayList<Relocation> list = new ArrayList<>(2);
+ list.add(uniqueRelocationTable.get(info.getSymbol()));
+ list.add(info);
+ relocationTable.put(info.getSymbol(), list);
+ uniqueRelocationTable.remove(info.getSymbol());
+ } else {
+ uniqueRelocationTable.put(info.getSymbol(), info);
+ }
+ }
+
+ /**
+ * Get symbol with name {@code symName}.
+ *
+ * @param symName name of symbol for which symbol table information is being queried
+ * @return success or failure of insertion operation
+ */
+ @Override
+ public Symbol getSymbol(String symName) {
+ return symbolTable.get(symName);
+ }
+
+ @Override
+ public Symbol createSymbol(int offset, Kind kind, Binding binding, int size, String name) {
+ if (kind != Kind.NATIVE_FUNCTION) {
+ throw new UnsupportedOperationException("Must be external functions: " + name);
+ }
+ Symbol symbol = new Symbol(offset, kind, binding, null, size, name);
+ addSymbol(symbol);
+ return symbol;
+ }
+
+ /**
+ * Get offset in got section with name {@code symName}.
+ *
+ * @param name for which String table information is being queried
+ * @return success or failure of insertion operation
+ */
+ public Integer getStringOffset(String name) {
+ return offsetStringTable.get(name);
+ }
+
+ /**
+ * Insert {@code targetCode} to code stream with {@code size} at {@code offset}.
+ *
+ * @param targetCode byte array of native code
+ * @param offset offset at which {@code targetCode} is to be inserted
+ * @param size size of {@code targetCode}
+ */
+ private static void appendBytes(ByteContainer byteContainer, byte[] targetCode, int offset, int size) {
+ byteContainer.appendBytes(targetCode, offset, size);
+ }
+
+ public void appendCodeBytes(byte[] targetCode, int offset, int size) {
+ appendBytes(codeContainer, targetCode, offset, size);
+ }
+
+ public void appendIntToCode(int value) {
+ codeContainer.appendInt(value);
+ }
+
+ public int appendExtLinkageGotBytes(byte[] bytes, int offset, int size) {
+ int startOffset = extLinkageGOTContainer.getByteStreamSize();
+ appendBytes(extLinkageGOTContainer, bytes, offset, size);
+ return startOffset;
+ }
+
+ public void addMetadataGotEntry(int offset) {
+ metadataGotContainer.appendLong(offset);
+ }
+
+ public int addMetaspaceName(String name) {
+ Integer value = metaspaceNames.get(name);
+ if (value != null) {
+ return value.intValue();
+ }
+ // Get the current length of the stubsNameContainer
+ // align on 8-byte boundary
+ int nameOffset = alignUp(metaspaceNamesContainer, 8);
+
+ try {
+ // Add the name of the symbol to the .stubs.names section
+ // Modify them to sequence of utf8 strings with length:
+ // "<u2_size>Ljava/lang/ThreadGroup;<u2_size>addUnstarted<u2_size>()V"
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(bout);
+ int len = name.length();
+ if (name.startsWith("Stub")) { // Stub
+ out.writeUTF(name);
+ } else { // Method or Klass
+ int parenthesesIndex = name.lastIndexOf('(', len - 1);
+ if (parenthesesIndex > 0) { // Method name
+ int dotIndex = name.lastIndexOf('.', parenthesesIndex - 1);
+ assert dotIndex > 0 : "method's full name should have '.' : " + name;
+ String klassName = name.substring(0, dotIndex);
+ out.writeUTF(klassName);
+ String methodName = name.substring(dotIndex + 1, parenthesesIndex);
+ out.writeUTF(methodName);
+ String signature = name.substring(parenthesesIndex, len);
+ out.writeUTF(signature);
+ } else {
+ out.writeUTF(name); // Klass
+ }
+ }
+ out.writeShort(0); // Terminate by 0.
+ byte[] b = bout.toByteArray();
+ metaspaceNamesContainer.appendBytes(b, 0, b.length);
+
+ metaspaceNames.put(name, nameOffset);
+ return nameOffset;
+ } catch (IOException e) {
+ throw new InternalError("Failed to append bytes to stubs sections", e);
+ }
+ }
+
+ /**
+ * Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to
+ * patch.
+ *
+ * @param oopName name of the oop symbol
+ */
+ public Integer addOopSymbol(String oopName) {
+ Integer oopGotOffset = getStringOffset(oopName);
+ if (oopGotOffset != null) {
+ return oopGotOffset;
+ }
+ return newOopSymbol(oopName);
+ }
+
+ private Integer newOopSymbol(String oopName) {
+ // Reference to String resolution (ldc).
+ int offset = oopGotContainer.getByteStreamSize();
+ String gotName = "got.ldc." + offset;
+ Symbol relocationSymbol = oopGotContainer.createGotSymbol(gotName);
+
+ if (offset != relocationSymbol.getOffset()) {
+ throw new InternalError("offset must equal! (" + offset + " vs " + relocationSymbol.getOffset());
+ }
+
+ addStringOffset(oopName, relocationSymbol.getOffset());
+ return relocationSymbol.getOffset();
+ }
+
+ public int addCountersSymbol(String metaspaceName) {
+ String gotName = "got." + metaspaceName;
+ Symbol relocationSymbol = getGotSymbol(gotName);
+ int metaspaceOffset = -1;
+ if (relocationSymbol == null) {
+ // Add slots when asked in the .metaspace.got section:
+ countersGotContainer.createGotSymbol(gotName);
+ }
+ return metaspaceOffset;
+ }
+
+ public Symbol getGotSymbol(String name) {
+ assert name.startsWith("got.");
+ return symbolTable.get(name);
+ }
+
+ /**
+ * Add klass symbol by as follows. - Adding the symbol name to the metaspace.names section - Add
+ * the offset of the name in metaspace.names to metaspace.offsets - Extend the klasses.got
+ * section with another slot for the VM to patch
+ *
+ * @param klassName name of the metaspace symbol
+ * @return the got offset in the klasses.got of the metaspace symbol
+ */
+ public int addTwoSlotKlassSymbol(String klassName) {
+ String gotName = "got." + klassName;
+ Symbol previous = getGotSymbol(gotName);
+ assert previous == null : "should be called only once for: " + klassName;
+ // Add slots when asked in the .metaspace.got section:
+ // First slot
+ String gotInitName = "got.init." + klassName;
+ GotSymbol slot1Symbol = klassesGotContainer.createGotSymbol(gotInitName);
+ GotSymbol slot2Symbol = klassesGotContainer.createGotSymbol(gotName);
+
+ slot1Symbol.getIndex(); // check alignment and ignore result
+ // Get the index (offset/8) to the got in the .metaspace.got section
+ return slot2Symbol.getIndex();
+ }
+
+ public static int addMethodsCount(int count, ReadOnlyDataContainer container) {
+ return appendInt(count, container);
+ }
+
+ private static int appendInt(int count, ReadOnlyDataContainer container) {
+ int offset = container.getByteStreamSize();
+ container.appendInt(count);
+ return offset;
+ }
+
+ /**
+ * Add constant data as follows. - Adding the data to the meth.constdata section
+ *
+ * @param data
+ * @param alignment
+ * @return the offset in the meth.constdata of the data
+ */
+ public int addConstantData(byte[] data, int alignment) {
+ // Get the current length of the metaspaceNameContainer
+ int constantDataOffset = alignUp(constantDataContainer, alignment);
+ constantDataContainer.appendBytes(data, 0, data.length);
+ alignUp(constantDataContainer, alignment); // Post alignment
+ return constantDataOffset;
+ }
+
+ public static int alignUp(ByteContainer container, int alignment) {
+ if (Integer.bitCount(alignment) != 1) {
+ throw new IllegalArgumentException("Must be a power of 2");
+ }
+ int offset = container.getByteStreamSize();
+ int aligned = (offset + (alignment - 1)) & -alignment;
+ if (aligned < offset || (aligned & (alignment - 1)) != 0) {
+ throw new RuntimeException("Error aligning: " + offset + " -> " + aligned);
+ }
+ if (aligned != offset) {
+ int nullArraySz = aligned - offset;
+ byte[] nullArray = new byte[nullArraySz];
+ container.appendBytes(nullArray, 0, nullArraySz);
+ offset = aligned;
+ }
+ return offset;
+ }
+
+ public void addCodeSegments(int start, int end) {
+ assert (start % codeSegmentSize) == 0 : "not aligned code";
+ int currentOffset = codeSegmentsContainer.getByteStreamSize();
+ int offset = start / codeSegmentSize;
+ int emptySize = offset - currentOffset;
+ // add empty segments if needed
+ if (emptySize > 0) {
+ byte[] emptyArray = new byte[emptySize];
+ for (int i = 0; i < emptySize; i++) {
+ emptyArray[i] = (byte) 0xff;
+ }
+ appendBytes(codeSegmentsContainer, emptyArray, 0, emptySize);
+ }
+ int alignedEnd = (end + (codeSegmentSize - 1)) & -codeSegmentSize;
+ int segmentsCount = (alignedEnd / codeSegmentSize) - offset;
+ byte[] segments = new byte[segmentsCount];
+ int idx = 0;
+ for (int i = 0; i < segmentsCount; i++) {
+ segments[i] = (byte) idx;
+ idx = (idx == 0xfe) ? 1 : (idx + 1);
+ }
+ appendBytes(codeSegmentsContainer, segments, 0, segmentsCount);
+ }
+
+ public ByteContainer getExtLinkageGOTContainer() {
+ return extLinkageGOTContainer;
+ }
+
+ public ReadOnlyDataContainer getMethodMetadataContainer() {
+ return methodMetadataContainer;
+ }
+
+ public ReadOnlyDataContainer getMetaspaceNamesContainer() {
+ return metaspaceNamesContainer;
+ }
+
+ public ReadOnlyDataContainer getMethodsOffsetsContainer() {
+ return methodsOffsetsContainer;
+ }
+
+ public ReadOnlyDataContainer getKlassesOffsetsContainer() {
+ return klassesOffsetsContainer;
+ }
+
+ public ReadOnlyDataContainer getKlassesDependenciesContainer() {
+ return klassesDependenciesContainer;
+ }
+
+ public ReadOnlyDataContainer getStubsOffsetsContainer() {
+ return stubsOffsetsContainer;
+ }
+
+ public ReadOnlyDataContainer getCodeSegmentsContainer() {
+ return codeSegmentsContainer;
+ }
+
+ public ReadOnlyDataContainer getConstantDataContainer() {
+ return constantDataContainer;
+ }
+
+ public ByteContainer getKlassesGotContainer() {
+ return klassesGotContainer;
+ }
+
+ public ByteContainer getCountersGotContainer() {
+ return countersGotContainer;
+ }
+
+ public ByteContainer getMetadataGotContainer() {
+ return metadataGotContainer;
+ }
+
+ public ByteContainer getMethodStateContainer() {
+ return methodStateContainer;
+ }
+
+ public ByteContainer getOopGotContainer() {
+ return oopGotContainer;
+ }
+
+ public CodeContainer getCodeContainer() {
+ return codeContainer;
+ }
+
+ public ReadOnlyDataContainer getConfigContainer() {
+ return configContainer;
+ }
+
+ public Map<Symbol, Relocation> getUniqueRelocationTable() {
+ return uniqueRelocationTable;
+ }
+
+ public HeaderContainer getHeaderContainer() {
+ return headerContainer;
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ByteContainer.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ByteContainer.java
new file mode 100644
index 000000000..e063759c3
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ByteContainer.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat;
+
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
+/**
+ * Base class that represents content of all sections with byte-level granularity. The ByteContainer
+ * class is backed by a ByteArrayOutputStream. This class supports writing all desired byte content
+ * to the container using the method {@code appendBytes} and accessing the byte array using the
+ * method {@code getByteArray}.
+ *
+ * The method {@code putIntAt} updates the content of {@code contentBytes}. Changes are not
+ * reflected in {@code contentStream}.
+ */
+public class ByteContainer implements Container {
+ /**
+ * {@code ByteBuffer} representation of {@code BinaryContainer}.
+ */
+ private ByteBuffer contentBytes;
+
+ /**
+ * {@code ByteArrayoutputStream} to which all appends are done.
+ */
+ private ByteArrayOutputStream contentStream;
+
+ /**
+ * Boolean to indicate if contentBytes was modified.
+ */
+ private boolean bufferModified;
+
+ /**
+ * Boolean to indicate if this section contains any relocations.
+ */
+ private boolean hasRelocations;
+
+ /**
+ * Name of this container, used as section name.
+ */
+ private String containerName;
+ private final SymbolTable symbolTable;
+
+ /**
+ * Contains a unique id.
+ */
+ private int sectionId = -1;
+
+ /**
+ * Construct a {@code ByteContainer} object.
+ */
+ public ByteContainer(String containerName, SymbolTable symbolTable) {
+ this.containerName = containerName;
+ this.symbolTable = symbolTable;
+ this.contentBytes = null;
+ this.bufferModified = false;
+ this.hasRelocations = false;
+ this.contentStream = new ByteArrayOutputStream();
+ }
+
+ /**
+ * Update byte buffer to reflect the current contents of byte stream.
+ *
+ * @throws InternalError throws {@code InternalError} if buffer byte array was modified
+ */
+ private void updateByteBuffer() {
+ if (!bufferModified) {
+ contentBytes = ByteBuffer.wrap(contentStream.toByteArray());
+ // Default byte order of ByteBuffer is BIG_ENDIAN.
+ // Set it appropriately
+ this.contentBytes.order(ByteOrder.nativeOrder());
+ } else {
+ throw new InternalError("Backing byte buffer no longer in sync with byte stream");
+ }
+ }
+
+ /**
+ * Get the byte array of {@code ByteContainer}.
+ *
+ * @return byte array
+ * @throws InternalError throws {@code InternalError} if buffer byte array was modified
+ */
+ public byte[] getByteArray() {
+ if (!bufferModified) {
+ updateByteBuffer();
+ }
+ return contentBytes.array();
+ }
+
+ /**
+ * Append to byte stream. It is an error to append to stream if the byte buffer version is
+ * changed.
+ *
+ * @param newBytes new content
+ * @param off offset start offset in {@code newBytes}
+ * @param len length of data to write
+ * @throws InternalError throws {@code InternalError} if buffer byte array was modified
+ */
+ public ByteContainer appendBytes(byte[] newBytes, int off, int len) {
+ if (bufferModified) {
+ throw new InternalError("Backing byte buffer no longer in sync with byte stream");
+ }
+ contentStream.write(newBytes, off, len);
+ return this;
+ }
+
+ public ByteContainer appendBytes(byte[] newBytes) {
+ appendBytes(newBytes, 0, newBytes.length);
+ return this;
+ }
+
+ public ByteContainer appendInt(int i) {
+ if (bufferModified) {
+ throw new InternalError("Backing byte buffer no longer in sync with byte stream");
+ }
+ ByteBuffer b = ByteBuffer.allocate(Integer.BYTES);
+ b.order(ByteOrder.nativeOrder());
+ b.putInt(i);
+ byte[] result = b.array();
+ contentStream.write(result, 0, result.length);
+ return this;
+ }
+
+ public ByteContainer appendInts(int[] newInts) {
+ if (bufferModified) {
+ throw new InternalError("Backing byte buffer no longer in sync with byte stream");
+ }
+ ByteBuffer b = ByteBuffer.allocate(Integer.BYTES * newInts.length).order(ByteOrder.nativeOrder());
+ Arrays.stream(newInts).forEach(i -> b.putInt(i));
+ byte[] result = b.array();
+ contentStream.write(result, 0, result.length);
+ return this;
+ }
+
+ public void appendLong(long l) {
+ if (bufferModified) {
+ throw new InternalError("Backing byte buffer no longer in sync with byte stream");
+ }
+ ByteBuffer b = ByteBuffer.allocate(8);
+ b.order(ByteOrder.nativeOrder());
+ b.putLong(l);
+ byte[] result = b.array();
+ contentStream.write(result, 0, result.length);
+ }
+
+ /**
+ * Return the current size of byte stream backing the BinaryContainer.
+ *
+ * @return size of buffer stream
+ */
+ public int getByteStreamSize() {
+ return contentStream.size();
+ }
+
+ /**
+ * Return the name of this container.
+ *
+ * @return string containing name
+ */
+ @Override
+ public String getContainerName() {
+ return containerName;
+ }
+
+ /**
+ * Modify the byte buffer version of the byte output stream. Note that after calling this method
+ * all further updates to BinaryContainer will be out of sync with byte buffer content.
+ *
+ * @param index index of byte to be changed
+ * @param value new value
+ */
+ public void putIntAt(int index, int value) {
+ if (!bufferModified) {
+ updateByteBuffer();
+ }
+ contentBytes.putInt(index, value);
+ bufferModified = true;
+ }
+
+ public void putLongAt(int index, long value) {
+ if (!bufferModified) {
+ updateByteBuffer();
+ }
+ contentBytes.putLong(index, value);
+ bufferModified = true;
+ }
+
+ public void setSectionId(int id) {
+ if (sectionId != -1) {
+ throw new InternalError("Assigning new sectionId (old: " + sectionId + ", new: " + id + ")");
+ }
+ sectionId = id;
+ }
+
+ @Override
+ public int getSectionId() {
+ if (sectionId == -1) {
+ throw new InternalError("Using sectionId before assigned");
+ }
+ return sectionId;
+ }
+
+ public Symbol createSymbol(int offset, Kind kind, Binding binding, int size, String name) {
+ Symbol symbol = new Symbol(offset, kind, binding, this, size, name);
+ symbolTable.addSymbol(symbol);
+ return symbol;
+ }
+
+ public GotSymbol createGotSymbol(String name) {
+ GotSymbol symbol = new GotSymbol(Kind.OBJECT, Binding.LOCAL, this, name);
+ symbolTable.addSymbol(symbol);
+ return symbol;
+ }
+
+ public GotSymbol createGotSymbol(int offset, String name) {
+ GotSymbol symbol = new GotSymbol(offset, Kind.OBJECT, Binding.LOCAL, this, name);
+ symbolTable.addSymbol(symbol);
+ return symbol;
+ }
+
+ public void clear() {
+ this.contentBytes = null;
+ this.contentStream = null;
+ }
+
+ public void setHasRelocations() {
+ this.hasRelocations = true;
+ }
+
+ public boolean hasRelocations() {
+ return this.hasRelocations;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/CodeContainer.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/CodeContainer.java
new file mode 100644
index 000000000..8b1f49812
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/CodeContainer.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat;
+
+/**
+ * A container that holds information about code section. This is simply a ByteContainer.
+ */
+public final class CodeContainer extends ByteContainer {
+
+ public CodeContainer(String containerName, SymbolTable symbolTable) {
+ super(containerName, symbolTable);
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Container.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Container.java
new file mode 100644
index 000000000..c12dc155b
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Container.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat;
+
+interface Container {
+
+ String getContainerName();
+
+ int getSectionId();
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/GotSymbol.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/GotSymbol.java
new file mode 100644
index 000000000..6c33e65da
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/GotSymbol.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat;
+
+public final class GotSymbol extends Symbol {
+
+ private static final int GOT_SIZE = 8;
+
+ public int getIndex() {
+ int offset = getOffset();
+ assert (offset % GOT_SIZE) == 0 : "got cells should be aligned: " + offset;
+ return offset / GOT_SIZE;
+ }
+
+ /**
+ * Create GOT symbol info.
+ *
+ * @param type type of the symbol (UNDEFINED, FUNC, etc)
+ * @param binding binding of the symbol (LOCAL, GLOBAL, ...)
+ * @param container section in which this symbol is "defined"
+ * @param name name of the symbol
+ */
+ public GotSymbol(Kind type, Binding binding, ByteContainer container, String name) {
+ this(container.getByteStreamSize(), type, binding, container, name);
+ container.appendBytes(new byte[GOT_SIZE], 0, GOT_SIZE);
+ }
+
+ /**
+ * Create GOT symbol info.
+ *
+ * @param offset section offset for the defined symbol
+ * @param type type of the symbol (UNDEFINED, FUNC, etc)
+ * @param binding binding of the symbol (LOCAL, GLOBAL, ...)
+ * @param sec section in which this symbol is "defined"
+ * @param name name of the symbol
+ */
+ public GotSymbol(int offset, Kind type, Binding binding, ByteContainer sec, String name) {
+ super(offset, type, binding, sec, GOT_SIZE, name);
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/HeaderContainer.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/HeaderContainer.java
new file mode 100644
index 000000000..78269a8cc
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/HeaderContainer.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public final class HeaderContainer {
+
+ private static final int CURRENT_VERSION = 1;
+ private final ReadOnlyDataContainer container;
+
+ // int _version;
+ // int _class_count;
+ // int _method_count;
+ // int _klasses_got_size;
+ // int _metadata_got_size;
+ // int _oop_got_size;
+ // int _jvm_version_offset;
+
+ public HeaderContainer(String jvmVersion, ReadOnlyDataContainer container) {
+ try {
+ byte[] filler = new byte[4 * 7];
+ container.appendBytes(filler);
+
+ // Store JVM version string at the end of header section.
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(bout);
+ out.writeUTF(jvmVersion);
+ out.writeShort(0); // Terminate by 0.
+ byte[] b = bout.toByteArray();
+ container.appendBytes(b, 0, b.length);
+ } catch (IOException e) {
+ throw new InternalError("Failed to append bytes to header section", e);
+ }
+
+ this.container = container;
+ this.container.putIntAt(0 * 4, CURRENT_VERSION);
+ this.container.putIntAt(6 * 4, 7 * 4); // JVM version string offset
+ }
+
+ public String getContainerName() {
+ return container.getContainerName();
+ }
+
+ public ReadOnlyDataContainer getContainer() {
+ return container;
+ }
+
+ public void setClassesCount(int count) {
+ this.container.putIntAt(1 * 4, count);
+ }
+
+ public void setMethodsCount(int count) {
+ this.container.putIntAt(2 * 4, count);
+ }
+
+ public void setKlassesGotSize(int size) {
+ this.container.putIntAt(3 * 4, size);
+ }
+
+ public void setMetadataGotSize(int size) {
+ this.container.putIntAt(4 * 4, size);
+ }
+
+ public void setOopGotSize(int size) {
+ this.container.putIntAt(5 * 4, size);
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/NativeSymbol.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/NativeSymbol.java
new file mode 100644
index 000000000..6deabe75f
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/NativeSymbol.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat;
+
+/**
+ * This class represents a native OS specific Symbol.
+ */
+public abstract class NativeSymbol {
+
+ /** String table index. */
+ private int index;
+
+ public NativeSymbol(int index) {
+ this.index = index;
+ }
+
+ /**
+ * @return the index
+ */
+ public int getIndex() {
+ return index;
+ }
+
+ /**
+ * @index
+ */
+ public void setIndex(int index) {
+ this.index = index;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ReadOnlyDataContainer.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ReadOnlyDataContainer.java
new file mode 100644
index 000000000..c96e27f4d
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ReadOnlyDataContainer.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat;
+
+public final class ReadOnlyDataContainer extends ByteContainer {
+
+ ReadOnlyDataContainer(String containerName, SymbolTable symbolTable) {
+ super(containerName, symbolTable);
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Relocation.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Relocation.java
new file mode 100644
index 000000000..5ff90bc6f
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Relocation.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat;
+
+public final class Relocation {
+
+ // @formatter:off (workaround for Eclipse formatting bug)
+ public enum RelocType {
+ UNDEFINED,
+ JAVA_CALL_INDIRECT,
+ JAVA_CALL_DIRECT,
+ FOREIGN_CALL_INDIRECT_GOT, // Call to address in GOT cell
+ STUB_CALL_DIRECT,
+ METASPACE_GOT_REFERENCE,
+ EXTERNAL_GOT_TO_PLT,
+ EXTERNAL_PLT_TO_GOT
+ }
+ // @formatter:on
+
+ private final RelocType type;
+
+ /**
+ * Byte offset from the beginning of the file affected by relocation.
+ */
+ private final int offset;
+
+ /**
+ * Size of relocation.
+ */
+ private final int size;
+
+ /**
+ * Symbol associated with this relocation.
+ */
+ private final Symbol symbol;
+
+ /**
+ * Section this relocation entry modifies.
+ */
+ private final ByteContainer section;
+
+ public Relocation(int offset, RelocType type, int size, ByteContainer section, Symbol sym) {
+ if (sym == null) {
+ throw new InternalError("must have symbol");
+ }
+ this.offset = offset;
+ this.type = type;
+ this.size = size;
+ this.symbol = sym;
+ this.section = section;
+ section.setHasRelocations();
+ }
+
+ public RelocType getType() {
+ return type;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public Symbol getSymbol() {
+ return symbol;
+ }
+
+ public ByteContainer getSection() {
+ return section;
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Symbol.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Symbol.java
new file mode 100644
index 000000000..26e458766
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Symbol.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat;
+
+import java.util.Objects;
+
+public class Symbol {
+
+ // @formatter:off (workaround for Eclipse formatting bug)
+ public enum Binding {
+ UNDEFINED,
+ LOCAL,
+ GLOBAL
+ }
+
+ public enum Kind {
+ UNDEFINED,
+ NATIVE_FUNCTION,
+ JAVA_FUNCTION,
+ OBJECT,
+ NOTYPE
+ }
+ // @formatter:on
+
+ private final String name;
+ private final int size;
+ private final int offset;
+ private final Binding binding;
+ private final Kind kind;
+
+ private ByteContainer section;
+ private NativeSymbol nativeSymbol;
+
+ /**
+ * Create symbol info.
+ *
+ * @param offset section offset for the defined symbol
+ * @param kind kind of the symbol (UNDEFINED, FUNC, etc)
+ * @param binding binding of the symbol (LOCAL, GLOBAL, ...)
+ * @param section section in which this symbol is "defined"
+ * @param size size of the symbol
+ * @param name name of the symbol
+ */
+
+ public Symbol(int offset, Kind kind, Binding binding, ByteContainer section, int size, String name) {
+ this.binding = binding;
+ this.kind = kind;
+ this.section = section;
+ this.size = size;
+ this.offset = offset;
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public NativeSymbol getNativeSymbol() {
+ return nativeSymbol;
+ }
+
+ public void setNativeSymbol(NativeSymbol nativeSym) {
+ this.nativeSymbol = nativeSym;
+ }
+
+ public Binding getBinding() {
+ return binding;
+ }
+
+ public Kind getKind() {
+ return kind;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public ByteContainer getSection() {
+ return section;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof Symbol)) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ Symbol symbol = (Symbol) obj;
+
+ if (size != symbol.size) {
+ return false;
+ }
+ if (offset != symbol.offset) {
+ return false;
+ }
+ if (!name.equals(symbol.name)) {
+ return false;
+ }
+ if (binding != symbol.binding) {
+ return false;
+ }
+ if (kind != symbol.kind) {
+ return false;
+ }
+ return !(section != null ? !section.equals(symbol.section) : symbol.section != null);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(name, binding, kind, section);
+ result = 31 * result + size;
+ result = 31 * result + offset;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "[" + name + ", " + size + ", " + offset + ", " + binding + ", " + kind + ", " + section + "]";
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/SymbolTable.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/SymbolTable.java
new file mode 100644
index 000000000..e2d4fe2cd
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/SymbolTable.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat;
+
+public interface SymbolTable {
+ void addSymbol(Symbol symInfo);
+
+ Symbol getSymbol(String symName);
+
+ Symbol createSymbol(int offset, Symbol.Kind kind, Symbol.Binding binding, int size, String name);
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/AArch64JELFRelocObject.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/AArch64JELFRelocObject.java
new file mode 100644
index 000000000..7d34d1b00
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/AArch64JELFRelocObject.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2023, Red Hat Inc. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.elf;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Relocation;
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+import jdk.tools.jaotc.binformat.Symbol;
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
+
+public class AArch64JELFRelocObject extends JELFRelocObject {
+
+ AArch64JELFRelocObject(BinaryContainer binContainer, String outputFileName) {
+ super(binContainer, outputFileName);
+ }
+
+ @Override
+ void createRelocation(Symbol symbol, Relocation reloc, ElfRelocTable elfRelocTable) {
+ RelocType relocType = reloc.getType();
+
+ int elfRelocType = getELFRelocationType(relocType);
+ ElfSymbol sym = (ElfSymbol) symbol.getNativeSymbol();
+ int symno = sym.getIndex();
+ int sectindex = reloc.getSection().getSectionId();
+ int offset = reloc.getOffset();
+ int addend = 0;
+
+ switch (relocType) {
+ case STUB_CALL_DIRECT:
+ case JAVA_CALL_DIRECT: {
+ break;
+ }
+ case EXTERNAL_PLT_TO_GOT:
+ offset -= 16;
+ elfRelocTable.createRelocationEntry(sectindex, offset, symno, Elf64_Rela.R_AARCH64_ADR_PREL_PG_HI21, addend);
+ elfRelocTable.createRelocationEntry(sectindex, offset + 4, symno, Elf64_Rela.R_AARCH64_ADD_ABS_LO12_NC, addend);
+ return;
+
+ case FOREIGN_CALL_INDIRECT_GOT: {
+ break;
+ }
+ case METASPACE_GOT_REFERENCE: {
+ offset -= 4;
+
+ elfRelocTable.createRelocationEntry(sectindex, offset, symno, Elf64_Rela.R_AARCH64_ADR_PREL_PG_HI21, addend);
+ elfRelocTable.createRelocationEntry(sectindex, offset + 4, symno, Elf64_Rela.R_AARCH64_ADD_ABS_LO12_NC, addend);
+ return;
+ }
+ // break;
+ case JAVA_CALL_INDIRECT: {
+ addend = -4;
+ offset = offset + addend;
+ break;
+ }
+ case EXTERNAL_GOT_TO_PLT: {
+ // this is load time relocations
+ break;
+ }
+ default:
+ throw new InternalError("Unhandled relocation type: " + relocType);
+ }
+
+ elfRelocTable.createRelocationEntry(sectindex, offset, symno, elfRelocType, addend);
+ }
+
+ int getELFRelocationType(RelocType relocType) {
+ int elfRelocType = 0; // R_<ARCH>_NONE if #define'd to 0 for all values of ARCH
+ switch (ElfTargetInfo.getElfArch()) {
+ case Elf64_Ehdr.EM_AARCH64:
+ // Return R_X86_64_* entries based on relocType
+ if (relocType == RelocType.JAVA_CALL_DIRECT ||
+ relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
+ elfRelocType = Elf64_Rela.R_AARCH64_CALL26;
+ } else if (relocType == RelocType.STUB_CALL_DIRECT) {
+ elfRelocType = Elf64_Rela.R_AARCH64_CALL26;
+ } else if (relocType == RelocType.JAVA_CALL_INDIRECT) {
+ elfRelocType = Elf64_Rela.R_AARCH64_CALL26;
+ } else if (relocType == RelocType.METASPACE_GOT_REFERENCE ||
+ relocType == RelocType.EXTERNAL_PLT_TO_GOT) {
+ elfRelocType = Elf64_Rela.R_AARCH64_NONE;
+ } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT) {
+ elfRelocType = Elf64_Rela.R_AARCH64_ABS64;
+ } else {
+ assert false : "Unhandled relocation type: " + relocType;
+ }
+ break;
+
+ default:
+ System.out.println("Relocation Type mapping: Unhandled architecture: " + ElfTargetInfo.getElfArch());
+ }
+ return elfRelocType;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/AMD64JELFRelocObject.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/AMD64JELFRelocObject.java
new file mode 100644
index 000000000..4f3b8d190
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/AMD64JELFRelocObject.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.elf;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Relocation;
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+import jdk.tools.jaotc.binformat.Symbol;
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
+
+public class AMD64JELFRelocObject extends JELFRelocObject {
+
+ AMD64JELFRelocObject(BinaryContainer binContainer, String outputFileName) {
+ super(binContainer, outputFileName);
+ }
+
+ @Override
+ protected void createRelocation(Symbol symbol, Relocation reloc, ElfRelocTable elfRelocTable) {
+ RelocType relocType = reloc.getType();
+
+ int elfRelocType = getELFRelocationType(relocType);
+ ElfSymbol sym = (ElfSymbol) symbol.getNativeSymbol();
+ int symno = sym.getIndex();
+ int sectindex = reloc.getSection().getSectionId();
+ int offset = reloc.getOffset();
+ int addend = 0;
+
+ switch (relocType) {
+ case JAVA_CALL_DIRECT:
+ case STUB_CALL_DIRECT:
+ case FOREIGN_CALL_INDIRECT_GOT: {
+ // Create relocation entry
+ addend = -4; // Size in bytes of the patch location
+ // Relocation should be applied at the location after call operand
+ offset = offset + reloc.getSize() + addend;
+ break;
+ }
+ case JAVA_CALL_INDIRECT:
+ case METASPACE_GOT_REFERENCE:
+ case EXTERNAL_PLT_TO_GOT: {
+ addend = -4; // Size of 32-bit address of the GOT
+ /*
+ * Relocation should be applied before the test instruction to the move instruction.
+ * reloc.getOffset() points to the test instruction after the instruction that loads
+ * the address of polling page. So set the offset appropriately.
+ */
+ offset = offset + addend;
+ break;
+ }
+ case EXTERNAL_GOT_TO_PLT: {
+ // this is load time relocations
+ break;
+ }
+ default:
+ throw new InternalError("Unhandled relocation type: " + relocType);
+ }
+ elfRelocTable.createRelocationEntry(sectindex, offset, symno, elfRelocType, addend);
+ }
+
+ private static int getELFRelocationType(RelocType relocType) {
+ int elfRelocType = 0; // R_<ARCH>_NONE if #define'd to 0 for all values of ARCH
+ switch (ElfTargetInfo.getElfArch()) {
+ case Elf64_Ehdr.EM_X86_64:
+ // Return R_X86_64_* entries based on relocType
+ if (relocType == RelocType.JAVA_CALL_DIRECT ||
+ relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
+ elfRelocType = Elf64_Rela.R_X86_64_PLT32;
+ } else if (relocType == RelocType.STUB_CALL_DIRECT) {
+ elfRelocType = Elf64_Rela.R_X86_64_PC32;
+ } else if (relocType == RelocType.JAVA_CALL_INDIRECT) {
+ elfRelocType = Elf64_Rela.R_X86_64_NONE;
+ } else if (relocType == RelocType.METASPACE_GOT_REFERENCE ||
+ relocType == RelocType.EXTERNAL_PLT_TO_GOT) {
+ elfRelocType = Elf64_Rela.R_X86_64_PC32;
+ } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT) {
+ elfRelocType = Elf64_Rela.R_X86_64_64;
+ } else {
+ assert false : "Unhandled relocation type: " + relocType;
+ }
+ break;
+
+ default:
+ System.out.println("Relocation Type mapping: Unhandled architecture: " + ElfTargetInfo.getElfArch());
+ }
+ return elfRelocType;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/Elf.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/Elf.java
new file mode 100644
index 000000000..35deca5b1
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/Elf.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2023, Red Hat Inc. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.elf;
+
+//@Checkstyle: stop
+//@formatter:off
+
+/**
+ * Support for the creation of Elf Object files. Current support is limited to 64 bit x86_64.
+ */
+final class Elf {
+ /**
+ * Elf64_Ehdr structure defines.
+ */
+ enum Elf64_Ehdr {
+ e_ident( 0,16),
+ e_type(16, 2),
+ e_machine(18, 2),
+ e_version(20, 4),
+ e_entry(24, 8),
+ e_phoff(32, 8),
+ e_shoff(40, 8),
+ e_flags(48, 4),
+ e_ehsize(52, 2),
+ e_phentsize(54, 2),
+ e_phnum(56, 2),
+ e_shentsize(58, 2),
+ e_shnum(60, 2),
+ e_shstrndx(62, 2);
+
+ final int off;
+ final int sz;
+
+ Elf64_Ehdr(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 64;
+
+ /**
+ * Elf64_Ehdr defines
+ */
+
+ /**
+ * e_ident
+ */
+ static final int EI_MAG0 = 0;
+ static final byte ELFMAG0 = 0x7f;
+ static final int EI_MAG1 = 1;
+ static final byte ELFMAG1 = 0x45;
+ static final int EI_MAG2 = 2;
+ static final byte ELFMAG2 = 0x4c;
+ static final int EI_MAG3 = 3;
+ static final byte ELFMAG3 = 0x46;
+ static final int EI_CLASS = 4;
+ static final byte ELFCLASS64 = 0x2;
+
+ static final int EI_DATA = 5;
+ static final byte ELFDATA2LSB = 0x1;
+
+ static final int EI_VERSION = 6;
+ static final byte EV_CURRENT = 0x1;
+
+ static final int EI_OSABI = 7;
+ static final byte ELFOSABI_NONE = 0x0;
+
+ /**
+ * e_type
+ */
+ static final char ET_REL = 0x1;
+
+ /**
+ * e_machine
+ */
+ static final char EM_NONE = 0;
+ static final char EM_X86_64 = 62;
+ static final char EM_AARCH64 = 183;
+
+ }
+
+ /**
+ * Elf64_Shdr structure defines.
+ */
+ enum Elf64_Shdr {
+ sh_name( 0, 4),
+ sh_type( 4, 4),
+ sh_flags( 8, 8),
+ sh_addr(16, 8),
+ sh_offset(24, 8),
+ sh_size(32, 8),
+ sh_link(40, 4),
+ sh_info(44, 4),
+ sh_addralign(48, 8),
+ sh_entsize(56, 8);
+
+ final int off;
+ final int sz;
+
+ Elf64_Shdr(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 64;
+
+ /**
+ * Elf64_Shdr defines
+ */
+
+ /**
+ * sh_type
+ */
+ static final int SHT_PROGBITS = 0x1;
+ static final int SHT_SYMTAB = 0x2;
+ static final int SHT_STRTAB = 0x3;
+ static final int SHT_RELA = 0x4;
+ static final int SHT_NOBITS = 0x8;
+ static final int SHT_REL = 0x9;
+
+ static final byte SHN_UNDEF = 0x0;
+
+ /**
+ * sh_flag
+ */
+ static final int SHF_WRITE = 0x1;
+ static final int SHF_ALLOC = 0x2;
+ static final int SHF_EXECINSTR = 0x4;
+
+ }
+
+ /**
+ * Symbol table entry definitions
+ *
+ * Elf64_Sym structure defines
+ */
+ enum Elf64_Sym {
+ st_name( 0, 4),
+ st_info( 4, 1),
+ st_other( 5, 1),
+ st_shndx( 6, 2),
+ st_value( 8, 8),
+ st_size(16, 8);
+
+ final int off;
+ final int sz;
+
+ Elf64_Sym(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 24;
+
+ /* ST_BIND is in bits 4-7 of st_info. ST_TYPE is in low 4 bits */
+ static final byte STB_LOCAL = 0x0;
+ static final byte STB_GLOBAL = 0x1;
+
+ static final byte STT_NOTYPE = 0x0;
+ static final byte STT_OBJECT = 0x1;
+ static final byte STT_FUNC = 0x2;
+
+ static byte ELF64_ST_INFO(byte bind, byte type) {
+ return (byte)(((bind) << 4) + ((type) & 0xf));
+ }
+
+ }
+
+ /**
+ * Elf64_Rel structure defines.
+ */
+ enum Elf64_Rel {
+ r_offset( 0, 8),
+ r_info( 8, 8);
+
+ final int off;
+ final int sz;
+
+ Elf64_Rel(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 16;
+
+ /**
+ * Relocation types.
+ */
+
+ static final int R_X86_64_NONE = 0x0;
+ static final int R_X86_64_64 = 0x1;
+ static final int R_X86_64_PC32 = 0x2;
+ static final int R_X86_64_PLT32 = 0x4;
+ static final int R_X86_64_GOTPCREL = 0x9;
+
+ static final int R_AARCH64_NONE = 256;
+ static final int R_AARCH64_ABS64 = 257;
+ static final int R_AARCH64_CALL26 = 283;
+ static final int R_AARCH64_ADR_GOT_PAGE = 311;
+ static final int R_AARCH64_LD64_GOT_LO12_NC = 312;
+
+ static final int R_AARCH64_MOVW_UABS_G0_NC = 264;
+ static final int R_AARCH64_MOVW_UABS_G1_NC = 266;
+ static final int R_AARCH64_MOVW_UABS_G2_NC = 268;
+
+ static final int R_AARCH64_ADR_PREL_PG_HI21 = 275;
+ static final int R_AARCH64_ADD_ABS_LO12_NC = 277;
+ static final int R_AARCH64_LDST64_ABS_LO12_NC = 286;
+ }
+
+ /**
+ * Elf64_Rela structure defines
+ */
+ enum Elf64_Rela {
+ r_offset( 0, 8),
+ r_info( 8, 8),
+ r_addend(16, 8);
+
+ final int off;
+ final int sz;
+
+ Elf64_Rela(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 24;
+
+ static final int R_X86_64_NONE = 0x0;
+ static final int R_X86_64_64 = 0x1;
+ static final int R_X86_64_PC32 = 0x2;
+ static final int R_X86_64_PLT32 = 0x4;
+ static final int R_X86_64_GOTPCREL = 0x9;
+
+ static final int R_AARCH64_NONE = 256;
+ static final int R_AARCH64_ABS64 = 257;
+ static final int R_AARCH64_CALL26 = 283;
+ static final int R_AARCH64_ADR_GOT_PAGE = 311;
+ static final int R_AARCH64_LD64_GOT_LO12_NC = 312;
+
+ static final int R_AARCH64_MOVW_UABS_G0_NC = 264;
+ static final int R_AARCH64_MOVW_UABS_G1_NC = 266;
+ static final int R_AARCH64_MOVW_UABS_G2_NC = 268;
+
+ static final int R_AARCH64_ADR_PREL_PG_HI21 = 275;
+ static final int R_AARCH64_ADD_ABS_LO12_NC = 277;
+ static final int R_AARCH64_LDST64_ABS_LO12_NC = 286;
+
+ static long ELF64_R_INFO(int symidx, int type) {
+ return (((long) symidx << 32) + type);
+ }
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfByteBuffer.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfByteBuffer.java
new file mode 100644
index 000000000..2f9c087e8
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfByteBuffer.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.elf;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
+
+final class ElfByteBuffer {
+
+ static ByteBuffer allocate(int size) {
+ ByteBuffer buf = ByteBuffer.allocate(size);
+ if (ElfTargetInfo.getElfEndian() == Elf64_Ehdr.ELFDATA2LSB) {
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ } else {
+ buf.order(ByteOrder.BIG_ENDIAN);
+ }
+ return (buf);
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfContainer.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfContainer.java
new file mode 100644
index 000000000..c3c8584bf
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfContainer.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.elf;
+
+import java.io.File;
+import java.io.FileOutputStream;
+
+final class ElfContainer {
+
+ private final File outputFile;
+ private FileOutputStream outputStream;
+ private long fileOffset;
+
+ ElfContainer(String fileName) {
+
+ outputFile = new File(fileName);
+ if (outputFile.exists()) {
+ outputFile.delete();
+ }
+
+ try {
+ outputStream = new FileOutputStream(outputFile);
+ } catch (Exception e) {
+ System.out.println("ElfContainer: Can't create file " + fileName);
+ }
+ fileOffset = 0;
+ }
+
+ void close() {
+ try {
+ outputStream.close();
+ } catch (Exception e) {
+ System.out.println("ElfContainer: close failed");
+ }
+ }
+
+ void writeBytes(byte[] bytes) {
+ if (bytes == null) {
+ return;
+ }
+ try {
+ outputStream.write(bytes);
+ } catch (Exception e) {
+ System.out.println("ElfContainer: writeBytes failed");
+ }
+ fileOffset += bytes.length;
+ }
+
+ // Write bytes to output file with up front alignment padding
+ void writeBytes(byte[] bytes, int alignment) {
+ if (bytes == null) {
+ return;
+ }
+ try {
+ // Pad to alignment
+ while ((fileOffset & (alignment - 1)) != 0) {
+ outputStream.write(0);
+ fileOffset++;
+ }
+ outputStream.write(bytes);
+ } catch (Exception e) {
+ System.out.println("ElfContainer: writeBytes failed");
+ }
+ fileOffset += bytes.length;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfHeader.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfHeader.java
new file mode 100644
index 000000000..463a681b9
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfHeader.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.elf;
+
+import java.nio.ByteBuffer;
+
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr;
+
+final class ElfHeader {
+ private final ByteBuffer header;
+
+ ElfHeader() {
+ header = ElfByteBuffer.allocate(Elf64_Ehdr.totalsize);
+
+ header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_MAG0, Elf64_Ehdr.ELFMAG0);
+ header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_MAG1, Elf64_Ehdr.ELFMAG1);
+ header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_MAG2, Elf64_Ehdr.ELFMAG2);
+ header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_MAG3, Elf64_Ehdr.ELFMAG3);
+ header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_CLASS, Elf64_Ehdr.ELFCLASS64);
+ header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_DATA, Elf64_Ehdr.ELFDATA2LSB);
+ header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_VERSION, Elf64_Ehdr.EV_CURRENT);
+ header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_OSABI, Elf64_Ehdr.ELFOSABI_NONE);
+
+ header.putChar(Elf64_Ehdr.e_type.off, Elf64_Ehdr.ET_REL);
+ header.putChar(Elf64_Ehdr.e_machine.off, ElfTargetInfo.getElfArch());
+ header.putInt(Elf64_Ehdr.e_version.off, Elf64_Ehdr.EV_CURRENT);
+ header.putChar(Elf64_Ehdr.e_ehsize.off, (char) Elf64_Ehdr.totalsize);
+ header.putChar(Elf64_Ehdr.e_shentsize.off, (char) Elf64_Shdr.totalsize);
+
+ }
+
+ // Update header with file offset of first section
+ void setSectionOff(int offset) {
+ header.putLong(Elf64_Ehdr.e_shoff.off, offset);
+ }
+
+ // Update header with the number of total sections
+ void setSectionNum(int count) {
+ header.putChar(Elf64_Ehdr.e_shnum.off, (char) count);
+ }
+
+ // Update header with the section index containing the
+ // string table for section names
+ void setSectionStrNdx(int index) {
+ header.putChar(Elf64_Ehdr.e_shstrndx.off, (char) index);
+ }
+
+ byte[] getArray() {
+ return header.array();
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocEntry.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocEntry.java
new file mode 100644
index 000000000..e0c70170a
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocEntry.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.elf;
+
+import java.nio.ByteBuffer;
+
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
+
+final class ElfRelocEntry {
+ private final ByteBuffer entry;
+
+ ElfRelocEntry(int offset, int symno, int type, int addend) {
+
+ entry = ElfByteBuffer.allocate(Elf64_Rela.totalsize);
+
+ entry.putLong(Elf64_Rela.r_offset.off, offset);
+ entry.putLong(Elf64_Rela.r_info.off, Elf64_Rela.ELF64_R_INFO(symno, type));
+ entry.putLong(Elf64_Rela.r_addend.off, addend);
+ }
+
+ byte[] getArray() {
+ return entry.array();
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocTable.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocTable.java
new file mode 100644
index 000000000..4a1504819
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocTable.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.elf;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
+
+final class ElfRelocTable {
+ private final ArrayList<ArrayList<ElfRelocEntry>> relocEntries;
+
+ ElfRelocTable(int numsects) {
+ relocEntries = new ArrayList<>(numsects);
+ for (int i = 0; i < numsects; i++) {
+ relocEntries.add(new ArrayList<ElfRelocEntry>());
+ }
+ }
+
+ void createRelocationEntry(int sectindex, int offset, int symno, int type, int addend) {
+ ElfRelocEntry entry = new ElfRelocEntry(offset, symno, type, addend);
+ relocEntries.get(sectindex).add(entry);
+ }
+
+ int getNumRelocs(int sectionIndex) {
+ return relocEntries.get(sectionIndex).size();
+ }
+
+ // Return the relocation entries for a single section
+ // or null if no entries added to section
+ byte[] getRelocData(int sectionIndex) {
+ ArrayList<ElfRelocEntry> entryList = relocEntries.get(sectionIndex);
+
+ if (entryList.size() == 0) {
+ return null;
+ }
+ ByteBuffer relocData = ElfByteBuffer.allocate(entryList.size() * Elf64_Rela.totalsize);
+
+ // Copy each entry to a single ByteBuffer
+ for (int i = 0; i < entryList.size(); i++) {
+ ElfRelocEntry entry = entryList.get(i);
+ relocData.put(entry.getArray());
+ }
+
+ return (relocData.array());
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSection.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSection.java
new file mode 100644
index 000000000..7e0168a85
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSection.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.elf;
+
+import java.nio.ByteBuffer;
+
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rel;
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr;
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym;
+
+final class ElfSection {
+ private final String name;
+ private final ByteBuffer section;
+ private final byte[] data;
+ private final boolean hasrelocations;
+ private final int sectionIndex;
+
+ /**
+ * String holding section name strings.
+ */
+ private static final StringBuilder sectNameTab = new StringBuilder();
+
+ /**
+ * Keeps track of bytes in section string table since strTabContent.length() is number of chars,
+ * not bytes.
+ */
+ private static int shStrTabNrOfBytes = 0;
+
+ ElfSection(String sectName, byte[] sectData, int sectFlags, int sectType,
+ boolean hasRelocations, int align, int sectIndex) {
+
+ section = ElfByteBuffer.allocate(Elf64_Shdr.totalsize);
+ name = sectName;
+ // Return all 0's for NULL section
+ if (sectIndex == 0) {
+ sectNameTab.append('\0');
+ shStrTabNrOfBytes += 1;
+ data = null;
+ hasrelocations = false;
+ sectionIndex = 0;
+ return;
+ }
+
+ section.putInt(Elf64_Shdr.sh_name.off, shStrTabNrOfBytes);
+ sectNameTab.append(sectName).append('\0');
+ shStrTabNrOfBytes += (sectName.getBytes().length + 1);
+
+ section.putInt(Elf64_Shdr.sh_type.off, sectType);
+ section.putLong(Elf64_Shdr.sh_flags.off, sectFlags);
+ section.putLong(Elf64_Shdr.sh_addr.off, 0);
+ section.putLong(Elf64_Shdr.sh_offset.off, 0);
+
+ if (sectName.equals(".shstrtab")) {
+ section.putLong(Elf64_Shdr.sh_size.off, shStrTabNrOfBytes);
+ data = sectNameTab.toString().getBytes();
+ } else {
+ data = sectData;
+ section.putLong(Elf64_Shdr.sh_size.off, sectData.length);
+ }
+
+ section.putLong(Elf64_Shdr.sh_entsize.off, 0);
+
+ // Determine the entrysize
+ // based on type of section
+ switch (sectType) {
+ case Elf64_Shdr.SHT_SYMTAB:
+ section.putLong(Elf64_Shdr.sh_entsize.off, Elf64_Sym.totalsize);
+ break;
+ case Elf64_Shdr.SHT_RELA:
+ section.putLong(Elf64_Shdr.sh_entsize.off, Elf64_Rela.totalsize);
+ break;
+ case Elf64_Shdr.SHT_REL:
+ section.putLong(Elf64_Shdr.sh_entsize.off, Elf64_Rel.totalsize);
+ break;
+ default:
+ break;
+ }
+ section.putLong(Elf64_Shdr.sh_addralign.off, align);
+
+ hasrelocations = hasRelocations;
+ sectionIndex = sectIndex;
+ }
+
+ String getName() {
+ return name;
+ }
+
+ long getSize() {
+ return section.getLong(Elf64_Shdr.sh_size.off);
+ }
+
+ int getDataAlign() {
+ return ((int) section.getLong(Elf64_Shdr.sh_addralign.off));
+ }
+
+ // Alignment requirements for the Elf64_Shdr structures
+ static int getShdrAlign() {
+ return (4);
+ }
+
+ byte[] getArray() {
+ return section.array();
+ }
+
+ byte[] getDataArray() {
+ return data;
+ }
+
+ void setOffset(long offset) {
+ section.putLong(Elf64_Shdr.sh_offset.off, offset);
+ }
+
+ void setLink(int link) {
+ section.putInt(Elf64_Shdr.sh_link.off, link);
+ }
+
+ void setInfo(int info) {
+ section.putInt(Elf64_Shdr.sh_info.off, info);
+ }
+
+ long getOffset() {
+ return (section.getLong(Elf64_Shdr.sh_offset.off));
+ }
+
+ boolean hasRelocations() {
+ return hasrelocations;
+ }
+
+ int getSectionId() {
+ return sectionIndex;
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymbol.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymbol.java
new file mode 100644
index 000000000..0f6e8d7fd
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymbol.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.elf;
+
+import java.nio.ByteBuffer;
+
+import jdk.tools.jaotc.binformat.NativeSymbol;
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym;
+
+final class ElfSymbol extends NativeSymbol {
+ private final ByteBuffer sym;
+
+ ElfSymbol(int symbolindex, int strindex, byte type, byte bind, byte sectindex, long offset, long size) {
+ super(symbolindex);
+ sym = ElfByteBuffer.allocate(Elf64_Sym.totalsize);
+
+ sym.putInt(Elf64_Sym.st_name.off, strindex);
+ sym.put(Elf64_Sym.st_info.off, Elf64_Sym.ELF64_ST_INFO(bind, type));
+ sym.put(Elf64_Sym.st_other.off, (byte) 0);
+ // Section indexes start at 1 but we manage the index internally
+ // as 0 relative
+ sym.putChar(Elf64_Sym.st_shndx.off, (char) (sectindex));
+ sym.putLong(Elf64_Sym.st_value.off, offset);
+ sym.putLong(Elf64_Sym.st_size.off, size);
+ }
+
+ byte[] getArray() {
+ return sym.array();
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymtab.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymtab.java
new file mode 100644
index 000000000..4cd26a5c0
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymtab.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.elf;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym;
+
+final class ElfSymtab {
+
+ private final ArrayList<ElfSymbol> localSymbols = new ArrayList<>();
+ private final ArrayList<ElfSymbol> globalSymbols = new ArrayList<>();
+
+ /**
+ * Number of symbols added.
+ */
+ private int symbolCount;
+
+ /**
+ * String holding symbol table strings.
+ */
+ private final StringBuilder strTabContent = new StringBuilder();
+
+ /**
+ * Keeps track of bytes in string table since strTabContent.length() is number of chars, not
+ * bytes.
+ */
+ private int strTabNrOfBytes = 0;
+
+ ElfSymtab() {
+ symbolCount = 0;
+ }
+
+ ElfSymbol addSymbolEntry(String name, byte type, byte bind, byte secHdrIndex, long offset, long size) {
+ // Get the current symbol index and append symbol name to string table.
+ int index;
+ ElfSymbol sym;
+
+ if (name.isEmpty()) {
+ index = 0;
+ strTabContent.append('\0');
+ strTabNrOfBytes += 1;
+ sym = new ElfSymbol(symbolCount, index, type, bind, secHdrIndex, offset, size);
+ localSymbols.add(sym);
+ } else {
+ // We can't trust strTabContent.length() since that is
+ // chars (UTF16), keep track of bytes on our own.
+ index = strTabNrOfBytes;
+ // strTabContent.append("_").append(name).append('\0');
+ strTabContent.append(name).append('\0');
+ // + 1 for null, + 1 for "_"
+ // strTabNrOfBytes += (name.getBytes().length + 1 + 1);
+ strTabNrOfBytes += (name.getBytes().length + 1);
+
+ sym = new ElfSymbol(symbolCount, index, type, bind, secHdrIndex, offset, size);
+ if ((bind & Elf64_Sym.STB_GLOBAL) != 0) {
+ globalSymbols.add(sym);
+ } else {
+ localSymbols.add(sym);
+ }
+ }
+ symbolCount++;
+ return (sym);
+ }
+
+ // Update the symbol indexes once all symbols have been added.
+ // This is required since we'll be reordering the symbols in the
+ // file to be in the order of Local then global.
+ void updateIndexes() {
+ int index = 0;
+
+ // Update the local symbol indexes
+ for (int i = 0; i < localSymbols.size(); i++) {
+ ElfSymbol sym = localSymbols.get(i);
+ sym.setIndex(index++);
+ }
+
+ // Update the global symbol indexes
+ for (int i = 0; i < globalSymbols.size(); i++) {
+ ElfSymbol sym = globalSymbols.get(i);
+ sym.setIndex(index++);
+ }
+ }
+
+ int getNumLocalSyms() {
+ return localSymbols.size();
+ }
+
+ int getNumGlobalSyms() {
+ return globalSymbols.size();
+ }
+
+ // Create a single byte array that contains the symbol table entries
+ byte[] getSymtabArray() {
+ ByteBuffer symtabData = ElfByteBuffer.allocate(symbolCount * Elf64_Sym.totalsize);
+ byte[] retarray;
+
+ updateIndexes();
+
+ // Add the local symbols
+ for (int i = 0; i < localSymbols.size(); i++) {
+ ElfSymbol sym = localSymbols.get(i);
+ byte[] arr = sym.getArray();
+ symtabData.put(arr);
+ }
+ // Add the global symbols
+ for (int i = 0; i < globalSymbols.size(); i++) {
+ ElfSymbol sym = globalSymbols.get(i);
+ byte[] arr = sym.getArray();
+ symtabData.put(arr);
+ }
+ retarray = symtabData.array();
+
+ return (retarray);
+ }
+
+ // Return the string table array
+ byte[] getStrtabArray() {
+ byte[] strs = strTabContent.toString().getBytes();
+ return (strs);
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfTargetInfo.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfTargetInfo.java
new file mode 100644
index 000000000..a29e7d3b5
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfTargetInfo.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.elf;
+
+import java.nio.ByteOrder;
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
+
+/**
+ * Class that abstracts MACH-O target details.
+ *
+ */
+final class ElfTargetInfo {
+ /**
+ * Target architecture.
+ */
+ private static final char arch;
+
+ /**
+ * Architecture endian-ness.
+ */
+ private static final int endian = Elf64_Ehdr.ELFDATA2LSB;
+
+ /**
+ * Target OS string.
+ */
+ private static String osName;
+
+ static {
+ // Find the target arch details
+ String archStr = System.getProperty("os.arch").toLowerCase();
+ if (ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN) {
+ System.out.println("Only Little Endian byte order supported!");
+ }
+
+ if (archStr.equals("amd64") || archStr.equals("x86_64")) {
+ arch = Elf64_Ehdr.EM_X86_64;
+ } else if (archStr.equals("aarch64")) {
+ arch = Elf64_Ehdr.EM_AARCH64;
+ } else {
+ System.out.println("Unsupported architecture " + archStr);
+ arch = Elf64_Ehdr.EM_NONE;
+ }
+
+ osName = System.getProperty("os.name").toLowerCase();
+ if (!osName.equals("linux")) {
+ System.out.println("Unsupported Operating System " + osName);
+ osName = "Unknown";
+ }
+ }
+
+ static char getElfArch() {
+ return arch;
+ }
+
+ static int getElfEndian() {
+ return endian;
+ }
+
+ static String getOsName() {
+ return osName;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/JELFRelocObject.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/JELFRelocObject.java
new file mode 100644
index 000000000..1f3251feb
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/JELFRelocObject.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.elf;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.ByteContainer;
+import jdk.tools.jaotc.binformat.CodeContainer;
+import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
+import jdk.tools.jaotc.binformat.Relocation;
+import jdk.tools.jaotc.binformat.Symbol;
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr;
+import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym;
+
+public abstract class JELFRelocObject {
+
+ private final BinaryContainer binContainer;
+
+ private final ElfContainer elfContainer;
+
+ private final int segmentSize;
+
+ protected JELFRelocObject(BinaryContainer binContainer, String outputFileName) {
+ this.binContainer = binContainer;
+ this.elfContainer = new ElfContainer(outputFileName);
+ this.segmentSize = binContainer.getCodeSegmentSize();
+ }
+
+ public static JELFRelocObject newInstance(BinaryContainer binContainer, String outputFileName) {
+ String archStr = System.getProperty("os.arch").toLowerCase();
+ if (archStr.equals("amd64") || archStr.equals("x86_64")) {
+ return new AMD64JELFRelocObject(binContainer, outputFileName);
+ } else if (archStr.equals("aarch64")) {
+ return new AArch64JELFRelocObject(binContainer, outputFileName);
+ }
+ throw new InternalError("Unsupported platform: " + archStr);
+ }
+
+ private static ElfSection createByteSection(ArrayList<ElfSection> sections,
+ String sectName,
+ byte[] scnData,
+ boolean hasRelocs,
+ int align,
+ int scnFlags,
+ int scnType) {
+
+ ElfSection sect = new ElfSection(sectName, scnData, scnFlags, scnType,
+ hasRelocs, align, sections.size());
+ // Add this section to our list
+ sections.add(sect);
+
+ return (sect);
+ }
+
+ private void createByteSection(ArrayList<ElfSection> sections,
+ ByteContainer c, int scnFlags) {
+ ElfSection sect;
+ boolean hasRelocs = c.hasRelocations();
+ byte[] scnData = c.getByteArray();
+
+ int scnType = Elf64_Shdr.SHT_PROGBITS;
+ boolean zeros = !hasRelocs;
+ if (zeros) {
+ for (byte b : scnData) {
+ if (b != 0) {
+ zeros = false;
+ break;
+ }
+ }
+ if (zeros) {
+ scnType = Elf64_Shdr.SHT_NOBITS;
+ }
+ }
+
+ sect = createByteSection(sections, c.getContainerName(),
+ scnData, hasRelocs, segmentSize,
+ scnFlags, scnType);
+ c.setSectionId(sect.getSectionId());
+ }
+
+ private void createCodeSection(ArrayList<ElfSection> sections, CodeContainer c) {
+ createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_EXECINSTR);
+ }
+
+ private void createReadOnlySection(ArrayList<ElfSection> sections, ReadOnlyDataContainer c) {
+ createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC);
+ }
+
+ private void createReadWriteSection(ArrayList<ElfSection> sections, ByteContainer c) {
+ createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_WRITE);
+ }
+
+ /**
+ * Creates an ELF relocatable object.
+ *
+ * @param relocationTable
+ * @param symbols
+ * @throws IOException throws {@code IOException} as a result of file system access failures.
+ */
+ public void createELFRelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException {
+ // Allocate ELF Header
+ ElfHeader eh = new ElfHeader();
+
+ ArrayList<ElfSection> sections = new ArrayList<>();
+
+ // Create the null section
+ createByteSection(sections, null, null, false, 1, 0, 0);
+
+ // Create text section
+ createCodeSection(sections, binContainer.getCodeContainer());
+ createReadOnlySection(sections, binContainer.getMetaspaceNamesContainer());
+ createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer());
+ createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer());
+ createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer());
+ createReadOnlySection(sections, binContainer.getMethodMetadataContainer());
+ createReadOnlySection(sections, binContainer.getStubsOffsetsContainer());
+ createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer());
+ createReadOnlySection(sections, binContainer.getCodeSegmentsContainer());
+ createReadOnlySection(sections, binContainer.getConstantDataContainer());
+ createReadOnlySection(sections, binContainer.getConfigContainer());
+ createReadWriteSection(sections, binContainer.getKlassesGotContainer());
+ createReadWriteSection(sections, binContainer.getCountersGotContainer());
+ createReadWriteSection(sections, binContainer.getMetadataGotContainer());
+ createReadWriteSection(sections, binContainer.getOopGotContainer());
+ createReadWriteSection(sections, binContainer.getMethodStateContainer());
+ createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer());
+
+ // Get ELF symbol data from BinaryContainer object's symbol tables
+ ElfSymtab symtab = createELFSymbolTables(symbols);
+
+ // Create string table section and symbol table sections in
+ // that order since symtab section needs to set the index of
+ // strtab in sh_link field
+ ElfSection strTabSection = createByteSection(sections, ".strtab",
+ symtab.getStrtabArray(),
+ false, 1, 0,
+ Elf64_Shdr.SHT_STRTAB);
+
+ // Now create .symtab section with the symtab data constructed.
+ // On Linux, sh_link of symtab contains the index of string table
+ // its symbols reference and sh_info contains the index of first
+ // non-local symbol
+ ElfSection symTabSection = createByteSection(sections, ".symtab",
+ symtab.getSymtabArray(),
+ false, 8, 0,
+ Elf64_Shdr.SHT_SYMTAB);
+ symTabSection.setLink(strTabSection.getSectionId());
+ symTabSection.setInfo(symtab.getNumLocalSyms());
+
+ ElfRelocTable elfRelocTable = createElfRelocTable(sections, relocationTable);
+
+ createElfRelocSections(sections, elfRelocTable, symTabSection.getSectionId());
+
+ // Now, finally, after creating all sections, create shstrtab section
+ ElfSection shStrTabSection = createByteSection(sections, ".shstrtab",
+ null, false, 1, 0,
+ Elf64_Shdr.SHT_STRTAB);
+ eh.setSectionStrNdx(shStrTabSection.getSectionId());
+
+ // Update all section offsets and the Elf header section offset
+ // Write the Header followed by the contents of each section
+ // and then the section structures (section table).
+ int fileOffset = Elf64_Ehdr.totalsize;
+
+ // and round it up
+ fileOffset = (fileOffset + (sections.get(1).getDataAlign() - 1)) &
+ ~((sections.get(1).getDataAlign() - 1));
+
+ // Calc file offsets for section data skipping null section
+ for (int i = 1; i < sections.size(); i++) {
+ ElfSection sect = sections.get(i);
+ fileOffset = (fileOffset + (sect.getDataAlign() - 1)) &
+ ~((sect.getDataAlign() - 1));
+ sect.setOffset(fileOffset);
+ fileOffset += sect.getSize();
+ }
+
+ // Align the section table
+ fileOffset = (fileOffset + (ElfSection.getShdrAlign() - 1)) &
+ ~((ElfSection.getShdrAlign() - 1));
+
+ // Update the Elf Header with the offset of the first Elf64_Shdr
+ // and the number of sections.
+ eh.setSectionOff(fileOffset);
+ eh.setSectionNum(sections.size());
+
+ // Write out the Header
+ elfContainer.writeBytes(eh.getArray());
+
+ // Write out each section contents skipping null section
+ for (int i = 1; i < sections.size(); i++) {
+ ElfSection sect = sections.get(i);
+ elfContainer.writeBytes(sect.getDataArray(), sect.getDataAlign());
+ }
+
+ // Write out the section table
+ for (int i = 0; i < sections.size(); i++) {
+ ElfSection sect = sections.get(i);
+ elfContainer.writeBytes(sect.getArray(), ElfSection.getShdrAlign());
+ }
+
+ elfContainer.close();
+ }
+
+ /**
+ * Construct ELF symbol data from BinaryContainer object's symbol tables. Both dynamic ELF
+ * symbol table and ELF symbol table are created from BinaryContainer's symbol info.
+ *
+ * @param symbols
+ */
+ private static ElfSymtab createELFSymbolTables(Collection<Symbol> symbols) {
+ ElfSymtab symtab = new ElfSymtab();
+
+ // First, create the initial null symbol. This is a local symbol.
+ symtab.addSymbolEntry("", (byte) 0, (byte) 0, Elf64_Shdr.SHN_UNDEF, 0, 0);
+
+ // Now create ELF symbol entries for all symbols.
+ for (Symbol symbol : symbols) {
+ // Get the index of section this symbol is defined in.
+ int secHdrIndex = symbol.getSection().getSectionId();
+ ElfSymbol elfSymbol = symtab.addSymbolEntry(symbol.getName(), getELFTypeOf(symbol), getELFBindOf(symbol), (byte) secHdrIndex, symbol.getOffset(), symbol.getSize());
+ symbol.setNativeSymbol(elfSymbol);
+ }
+ return (symtab);
+ }
+
+ private static byte getELFTypeOf(Symbol sym) {
+ Kind kind = sym.getKind();
+ if (kind == Symbol.Kind.NATIVE_FUNCTION || kind == Symbol.Kind.JAVA_FUNCTION) {
+ return Elf64_Sym.STT_FUNC;
+ } else if (kind == Symbol.Kind.OBJECT) {
+ return Elf64_Sym.STT_OBJECT;
+ }
+ return Elf64_Sym.STT_NOTYPE;
+ }
+
+ private static byte getELFBindOf(Symbol sym) {
+ Binding binding = sym.getBinding();
+ if (binding == Symbol.Binding.GLOBAL) {
+ return Elf64_Sym.STB_GLOBAL;
+ }
+ return Elf64_Sym.STB_LOCAL;
+ }
+
+ /**
+ * Construct a Elf relocation table from BinaryContainer object's relocation tables.
+ *
+ * @param sections
+ * @param relocationTable
+ */
+ private ElfRelocTable createElfRelocTable(ArrayList<ElfSection> sections,
+ Map<Symbol, List<Relocation>> relocationTable) {
+
+ ElfRelocTable elfRelocTable = new ElfRelocTable(sections.size());
+ /*
+ * For each of the symbols with associated relocation records, create a Elf relocation
+ * entry.
+ */
+ for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) {
+ List<Relocation> relocs = entry.getValue();
+ Symbol symbol = entry.getKey();
+
+ for (Relocation reloc : relocs) {
+ createRelocation(symbol, reloc, elfRelocTable);
+ }
+ }
+
+ for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) {
+ createRelocation(entry.getKey(), entry.getValue(), elfRelocTable);
+ }
+
+ return (elfRelocTable);
+ }
+
+ private static void createElfRelocSections(ArrayList<ElfSection> sections,
+ ElfRelocTable elfRelocTable,
+ int symtabsectidx) {
+
+ // Grab count before we create new sections
+ int count = sections.size();
+
+ for (int i = 0; i < count; i++) {
+ if (elfRelocTable.getNumRelocs(i) > 0) {
+ ElfSection sect = sections.get(i);
+ String relname = ".rela" + sect.getName();
+ ElfSection relocSection = createByteSection(sections, relname,
+ elfRelocTable.getRelocData(i),
+ false, 8, 0, Elf64_Shdr.SHT_RELA);
+ relocSection.setLink(symtabsectidx);
+ relocSection.setInfo(sect.getSectionId());
+ }
+ }
+ }
+
+ abstract void createRelocation(Symbol symbol, Relocation reloc, ElfRelocTable elfRelocTable);
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/JMachORelocObject.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/JMachORelocObject.java
new file mode 100644
index 000000000..e6068e118
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/JMachORelocObject.java
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ *
+ * File Layout generated by JMachORelocObject
+ *
+ * MachO Header
+ * Load Commands
+ * LC_SEGMENT_64
+ * - Sections
+ * LC_VERSION_MIN_MAX
+ * LC_SYMTAB
+ * LC_DYSYMTAB
+ * Section Data
+ * Relocation entries
+ * Symbol table
+ *
+ */
+
+
+
+package jdk.tools.jaotc.binformat.macho;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.ByteContainer;
+import jdk.tools.jaotc.binformat.CodeContainer;
+import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
+import jdk.tools.jaotc.binformat.Relocation;
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+import jdk.tools.jaotc.binformat.Symbol;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+import jdk.tools.jaotc.binformat.macho.MachO.dysymtab_command;
+import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64;
+import jdk.tools.jaotc.binformat.macho.MachO.nlist_64;
+import jdk.tools.jaotc.binformat.macho.MachO.reloc_info;
+import jdk.tools.jaotc.binformat.macho.MachO.section_64;
+import jdk.tools.jaotc.binformat.macho.MachO.segment_command_64;
+import jdk.tools.jaotc.binformat.macho.MachO.symtab_command;
+import jdk.tools.jaotc.binformat.macho.MachO.version_min_command;
+
+public class JMachORelocObject {
+
+ private final BinaryContainer binContainer;
+
+ private final MachOContainer machoContainer;
+
+ private final int segmentSize;
+
+ public JMachORelocObject(BinaryContainer binContainer, String outputFileName) {
+ this.binContainer = binContainer;
+ this.machoContainer = new MachOContainer(outputFileName);
+ this.segmentSize = binContainer.getCodeSegmentSize();
+ }
+
+ private void createByteSection(ArrayList<MachOSection> sections,
+ ByteContainer c, String sectName, String segName, int scnFlags) {
+
+ if (c.getByteArray().length == 0) {
+ // System.out.println("Skipping creation of " + sectName + " section, no data\n");
+ }
+
+ MachOSection sect = new MachOSection(sectName,
+ segName,
+ c.getByteArray(),
+ scnFlags,
+ c.hasRelocations(),
+ segmentSize);
+ // Add this section to our list
+ sections.add(sect);
+
+ // Record the section Id (0 relative)
+ c.setSectionId(sections.size() - 1);
+
+ // TODO: Clear out code section data to allow for GC
+ // c.clear();
+ }
+
+ private void createCodeSection(ArrayList<MachOSection> sections, CodeContainer c) {
+ createByteSection(sections, c, /* c.getContainerName() */ "__text", "__TEXT",
+ section_64.S_ATTR_PURE_INSTRUCTIONS |
+ section_64.S_ATTR_SOME_INSTRUCTIONS);
+ }
+
+ private void createReadOnlySection(ArrayList<MachOSection> sections, ReadOnlyDataContainer c) {
+ createByteSection(sections, c, c.getContainerName(), "__TEXT",
+ section_64.S_ATTR_SOME_INSTRUCTIONS);
+ }
+
+ private void createReadWriteSection(ArrayList<MachOSection> sections, ByteContainer c) {
+ createByteSection(sections, c, c.getContainerName(), "__DATA", section_64.S_REGULAR);
+ }
+
+ /**
+ * Creates an MachO relocatable object.
+ *
+ * @param relocationTable
+ * @param symbols
+ * @throws IOException throws {@code IOException} as a result of file system access failures.
+ */
+ public void createMachORelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException {
+ // Allocate MachO Header
+ // with 4 load commands
+ // LC_SEGMENT_64
+ // LC_VERSION_MIN_MACOSX
+ // LC_SYMTAB
+ // LC_DYSYMTAB
+
+ MachOHeader mh = new MachOHeader();
+
+ ArrayList<MachOSection> sections = new ArrayList<>();
+
+ // Create Sections contained in the main Segment LC_SEGMENT_64
+
+ createCodeSection(sections, binContainer.getCodeContainer());
+ createReadOnlySection(sections, binContainer.getMetaspaceNamesContainer());
+ createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer());
+ createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer());
+ createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer());
+ createReadOnlySection(sections, binContainer.getMethodMetadataContainer());
+ createReadOnlySection(sections, binContainer.getStubsOffsetsContainer());
+ createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer());
+ createReadOnlySection(sections, binContainer.getCodeSegmentsContainer());
+ createReadOnlySection(sections, binContainer.getConstantDataContainer());
+ createReadOnlySection(sections, binContainer.getConfigContainer());
+ createReadWriteSection(sections, binContainer.getKlassesGotContainer());
+ createReadWriteSection(sections, binContainer.getCountersGotContainer());
+ createReadWriteSection(sections, binContainer.getMetadataGotContainer());
+ createReadWriteSection(sections, binContainer.getMethodStateContainer());
+ createReadWriteSection(sections, binContainer.getOopGotContainer());
+ createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer());
+
+ // Update the Header sizeofcmds size.
+ // This doesn't include the Header struct size
+ mh.setCmdSizes(4, segment_command_64.totalsize +
+ (section_64.totalsize * sections.size()) +
+ version_min_command.totalsize +
+ symtab_command.totalsize +
+ dysymtab_command.totalsize);
+
+ // Initialize file offset for data past commands
+ int fileOffset = mach_header_64.totalsize + mh.getCmdSize();
+ // and round it up
+ fileOffset = (fileOffset + (sections.get(0).getAlign() - 1)) & ~((sections.get(0).getAlign() - 1));
+ long address = 0;
+ int segmentOffset = fileOffset;
+
+ for (int i = 0; i < sections.size(); i++) {
+ MachOSection sect = sections.get(i);
+ fileOffset = (fileOffset + (sect.getAlign() - 1)) & ~((sect.getAlign() - 1));
+ address = (address + (sect.getAlign() - 1)) & ~((sect.getAlign() - 1));
+ sect.setOffset(fileOffset);
+ sect.setAddr(address);
+ fileOffset += sect.getSize();
+ address += sect.getSize();
+ }
+
+ // File size for Segment data
+ int segSize = fileOffset - segmentOffset;
+
+ // Create the LC_SEGMENT_64 Segment which contains the MachOSections
+ MachOSegment seg = new MachOSegment(segment_command_64.totalsize +
+ (section_64.totalsize * sections.size()),
+ segmentOffset,
+ segSize,
+ sections.size());
+
+ MachOVersion vers = new MachOVersion();
+
+ // Get symbol data from BinaryContainer object's symbol tables
+ MachOSymtab symtab = createMachOSymbolTables(sections, symbols);
+
+ // Create LC_DYSYMTAB command
+ MachODySymtab dysymtab = new MachODySymtab(symtab.getNumLocalSyms(),
+ symtab.getNumGlobalSyms(),
+ symtab.getNumUndefSyms());
+
+ // Create the Relocation Tables
+ MachORelocTable machORelocs = createMachORelocTable(sections, relocationTable, symtab);
+ // Calculate file offset for relocation data
+ fileOffset = (fileOffset + (MachORelocTable.getAlign() - 1)) & ~((MachORelocTable.getAlign() - 1));
+
+ // Update relocation sizing information in each section
+ for (int i = 0; i < sections.size(); i++) {
+ MachOSection sect = sections.get(i);
+ if (sect.hasRelocations()) {
+ int nreloc = machORelocs.getNumRelocs(i);
+ sect.setReloff(fileOffset);
+ sect.setRelcount(nreloc);
+ fileOffset += (nreloc * reloc_info.totalsize);
+ }
+ }
+
+ // Calculate and set file offset for symbol table data
+ fileOffset = (fileOffset + (MachOSymtab.getAlign() - 1)) & ~((MachOSymtab.getAlign() - 1));
+ symtab.setOffset(fileOffset);
+
+ // Write Out Header
+ machoContainer.writeBytes(mh.getArray());
+ // Write out first Segment
+ machoContainer.writeBytes(seg.getArray());
+ // Write out sections within first Segment
+ for (int i = 0; i < sections.size(); i++) {
+ MachOSection sect = sections.get(i);
+ machoContainer.writeBytes(sect.getArray());
+ }
+
+ // Write out LC_VERSION_MIN_MACOSX command
+ machoContainer.writeBytes(vers.getArray());
+
+ // Write out LC_SYMTAB command
+ symtab.calcSizes();
+ machoContainer.writeBytes(symtab.getCmdArray());
+
+ // Write out LC_DYSYMTAB command
+ machoContainer.writeBytes(dysymtab.getArray());
+
+ // Write out data associated with each Section
+ for (int i = 0; i < sections.size(); i++) {
+ MachOSection sect = sections.get(i);
+ machoContainer.writeBytes(sect.getDataArray(), sect.getAlign());
+ }
+
+ // Write out the relocation tables for all sections
+ for (int i = 0; i < sections.size(); i++) {
+ if (machORelocs.getNumRelocs(i) > 0) {
+ machoContainer.writeBytes(machORelocs.getRelocData(i), MachORelocTable.getAlign());
+ }
+ }
+
+ // Write out data associated with LC_SYMTAB
+ machoContainer.writeBytes(symtab.getDataArray(), MachOSymtab.getAlign());
+
+ machoContainer.close();
+ }
+
+ /**
+ * Construct MachO symbol data from BinaryContainer object's symbol tables. Both dynamic MachO
+ * symbol table and MachO symbol table are created from BinaryContainer's symbol info.
+ *
+ * @param sections
+ * @param symbols
+ */
+ private static MachOSymtab createMachOSymbolTables(ArrayList<MachOSection> sections,
+ Collection<Symbol> symbols) {
+ MachOSymtab symtab = new MachOSymtab();
+ // First, create the initial null symbol. This is a local symbol.
+ symtab.addSymbolEntry("", (byte) nlist_64.N_UNDF, (byte) 0, 0);
+
+ // Now create MachO symbol entries for all symbols.
+ for (Symbol symbol : symbols) {
+ int sectionId = symbol.getSection().getSectionId();
+
+ // Symbol offsets are relative to the section memory addr
+ long sectionAddr = sections.get(sectionId).getAddr();
+
+ MachOSymbol machoSymbol = symtab.addSymbolEntry(symbol.getName(),
+ getMachOTypeOf(symbol),
+ (byte) sectionId,
+ symbol.getOffset() + sectionAddr);
+ symbol.setNativeSymbol(machoSymbol);
+ }
+
+ // Now that all symbols are enterred, update the
+ // symbol indexes. This is necessary since they will
+ // be reordered based on local, global and undefined.
+ symtab.updateIndexes();
+
+ return (symtab);
+ }
+
+ private static byte getMachOTypeOf(Symbol sym) {
+ Kind kind = sym.getKind();
+ byte type = nlist_64.N_UNDF;
+
+ // Global or Local
+ if (sym.getBinding() == Symbol.Binding.GLOBAL) {
+ type = nlist_64.N_EXT;
+ }
+ // If Function or Data, add section type
+ if (kind == Symbol.Kind.NATIVE_FUNCTION ||
+ kind == Symbol.Kind.JAVA_FUNCTION ||
+ kind == Symbol.Kind.OBJECT) {
+ type |= (nlist_64.N_SECT);
+ }
+
+ return (type);
+ }
+
+ /**
+ * Construct a MachO relocation table from BinaryContainer object's relocation tables.
+ *
+ * @param sections
+ * @param relocationTable
+ * @param symtab
+ */
+ private MachORelocTable createMachORelocTable(ArrayList<MachOSection> sections,
+ Map<Symbol, List<Relocation>> relocationTable,
+ MachOSymtab symtab) {
+
+ MachORelocTable machORelocTable = new MachORelocTable(sections.size());
+ /*
+ * For each of the symbols with associated relocation records, create a MachO relocation
+ * entry.
+ */
+ for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) {
+ List<Relocation> relocs = entry.getValue();
+ Symbol symbol = entry.getKey();
+
+ for (Relocation reloc : relocs) {
+ createRelocation(symbol, reloc, machORelocTable);
+ }
+ }
+
+ for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) {
+ createRelocation(entry.getKey(), entry.getValue(), machORelocTable);
+ }
+
+ return (machORelocTable);
+ }
+
+ private static void createRelocation(Symbol symbol, Relocation reloc, MachORelocTable machORelocTable) {
+ RelocType relocType = reloc.getType();
+
+ int machORelocType = getMachORelocationType(relocType);
+ MachOSymbol sym = (MachOSymbol) symbol.getNativeSymbol();
+ int symno = sym.getIndex();
+ int sectindex = reloc.getSection().getSectionId();
+ int offset = reloc.getOffset();
+ int pcrel = 0;
+ int length = 0;
+ int isextern = 1;
+
+ switch (relocType) {
+ case JAVA_CALL_DIRECT:
+ case STUB_CALL_DIRECT:
+ case FOREIGN_CALL_INDIRECT_GOT: {
+ // Create relocation entry
+ int addend = -4; // Size in bytes of the patch location
+ // Relocation should be applied at the location after call operand
+ offset = offset + reloc.getSize() + addend;
+ pcrel = 1;
+ length = 2;
+ break;
+ }
+ case JAVA_CALL_INDIRECT: {
+ // Do nothing.
+ return;
+ }
+ case METASPACE_GOT_REFERENCE:
+ case EXTERNAL_PLT_TO_GOT: {
+ int addend = -4; // Size of 32-bit address of the GOT
+ /*
+ * Relocation should be applied before the test instruction to the move instruction.
+ * reloc.getOffset() points to the test instruction after the instruction that loads
+ * the address of polling page. So set the offset appropriately.
+ */
+ offset = offset + addend;
+ pcrel = 1;
+ length = 2;
+ break;
+ }
+ case EXTERNAL_GOT_TO_PLT: {
+ // this is load time relocations
+ pcrel = 0;
+ length = 3;
+ break;
+ }
+ default:
+ throw new InternalError("Unhandled relocation type: " + relocType);
+ }
+ machORelocTable.createRelocationEntry(sectindex, offset, symno,
+ pcrel, length, isextern,
+ machORelocType);
+ }
+
+ private static int getMachORelocationType(RelocType relocType) {
+ int machORelocType = 0;
+ switch (MachOTargetInfo.getMachOArch()) {
+ case mach_header_64.CPU_TYPE_X86_64:
+ // Return X86_64_RELOC_* entries based on relocType
+ if (relocType == RelocType.JAVA_CALL_DIRECT ||
+ relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
+ machORelocType = reloc_info.X86_64_RELOC_BRANCH;
+ } else if (relocType == RelocType.STUB_CALL_DIRECT) {
+ machORelocType = reloc_info.X86_64_RELOC_BRANCH;
+ } else if (relocType == RelocType.JAVA_CALL_INDIRECT) {
+ machORelocType = reloc_info.X86_64_RELOC_NONE;
+ } else if (relocType == RelocType.METASPACE_GOT_REFERENCE ||
+ relocType == RelocType.EXTERNAL_PLT_TO_GOT) {
+ machORelocType = reloc_info.X86_64_RELOC_BRANCH;
+ } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT) {
+ machORelocType = reloc_info.X86_64_RELOC_UNSIGNED;
+ } else {
+ assert false : "Unhandled relocation type: " + relocType;
+ }
+ break;
+ default:
+ System.out.println("Relocation Type mapping: Unhandled architecture");
+ }
+ return machORelocType;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachO.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachO.java
new file mode 100644
index 000000000..49d239b20
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachO.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.macho;
+
+//@formatter:off
+//@Checkstyle: stop
+
+/**
+ *
+ * Support for the creation of Mach-o Object files. Current support is limited to 64 bit x86_64.
+ *
+ * File Format Overview:
+ *
+ * mach_header
+ * load_commands
+ * Typical Mac OSX 64-bit object files have these 4 load_commands
+ * (LC_SEGMENT_64, LC_SYMTAB, LC_VERSIN_MIN_MACOSX, LC_DYSYMTAB)
+ * Segments corresponding to load_commands
+ * (which each include multiple Sections)
+ */
+
+final class MachO {
+
+ /**
+ * mach_header_64 structure defines
+ */
+ enum mach_header_64 {
+ magic( 0, 4),
+ cputype( 4, 4),
+ cpusubtype( 8, 4),
+ filetype(12, 4),
+ ncmds(16, 4),
+ sizeofcmds(20, 4),
+ flags(24, 4),
+ reserved(28, 4);
+
+ final int off;
+ final int sz;
+
+ mach_header_64(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 32;
+
+ /**
+ * mach_header_64 defines
+ */
+ static final int MH_MAGIC = 0xfeedface;
+ static final int MH_MAGIC_64 = 0xfeedfacf;
+ static final int MH_SUBSECTIONS_VIA_SYMBOLS = 0x2000;
+
+ /**
+ * filetype
+ */
+ static final int MH_OBJECT = 0x1;
+
+ /**
+ * cputype
+ */
+ static final int CPU_TYPE_ANY = -1;
+ static final int CPU_ARCH_ABI64 = 0x1000000;
+ static final int CPU_TYPE_X86_64 = 0x1000007;
+ static final int CPU_TYPE_ARM64 = 0x100000c;
+ /**
+ * cpusubtype
+ */
+ static final int CPU_SUBTYPE_I386_ALL = 3;
+ static final int CPU_SUBTYPE_ARM64_ALL = 0;
+ static final int CPU_SUBTYPE_LITTLE_ENDIAN = 0;
+ static final int CPU_SUBTYPE_BIG_ENDIAN = 1;
+
+ }
+
+ /**
+ * segment_command_64 structure defines
+ */
+ enum segment_command_64 {
+ cmd( 0, 4),
+ cmdsize( 4, 4),
+ segname( 8,16),
+ vmaddr(24, 8),
+ vmsize(32, 8),
+ fileoff(40, 8),
+ filesize(48, 8),
+ maxprot(56, 4),
+ initprot(60, 4),
+ nsects(64, 4),
+ flags(68, 4);
+
+ final int off;
+ final int sz;
+
+ segment_command_64(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 72;
+
+ static final int LC_SEGMENT_64 = 0x19;
+ }
+
+ /**
+ * section_64 structure defines
+ */
+ enum section_64 {
+ sectname( 0,16),
+ segname(16,16),
+ addr(32, 8),
+ size(40, 8),
+ offset(48, 4),
+ align(52, 4),
+ reloff(56, 4),
+ nreloc(60, 4),
+ flags(64, 4),
+ reserved1(68, 4),
+ reserved2(72, 4),
+ reserved3(76, 4);
+
+ final int off;
+ final int sz;
+
+ section_64(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 80;
+
+ static int S_REGULAR = 0x0;
+ static int S_CSTRING_LITERALS = 0x2;
+ static int S_ATTR_PURE_INSTRUCTIONS = 0x80000000;
+ static int S_ATTR_SOME_INSTRUCTIONS = 0x400;
+ }
+
+ /**
+ * version_min_command structure defines
+ */
+ enum version_min_command {
+ cmd( 0, 4),
+ cmdsize( 4, 4),
+ version( 8, 4),
+ sdk(12, 4);
+
+ final int off;
+ final int sz;
+
+ version_min_command(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 16;
+
+ static final int LC_VERSION_MIN_MACOSX = 0x24;
+ static final int LC_VERSION_MIN_IPHONEOS = 0x25;
+ }
+
+ /**
+ * symtab_command structure defines
+ */
+ enum symtab_command {
+ cmd( 0, 4),
+ cmdsize( 4, 4),
+ symoff( 8, 4),
+ nsyms(12, 4),
+ stroff(16, 4),
+ strsize(20, 4);
+
+ final int off;
+ final int sz;
+
+ symtab_command(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 24;
+
+ static final int LC_SYMTAB = 0x2;
+ }
+
+ /**
+ * Symbol table entry definitions
+ *
+ * nlist_64 structure defines
+ */
+ enum nlist_64 {
+ n_strx( 0, 4),
+ n_type( 4, 1),
+ n_sect( 5, 1),
+ n_desc( 6, 2),
+ n_value( 8, 8);
+
+ final int off;
+ final int sz;
+
+ nlist_64(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 16;
+
+ static final int N_EXT = 0x1;
+ static final int N_TYPE = 0xe;
+ static final int N_UNDF = 0x0;
+ static final int N_SECT = 0xe;
+ }
+
+ /**
+ * dysymtab_command structure defines
+ */
+ enum dysymtab_command {
+ cmd( 0, 4),
+ cmdsize( 4, 4),
+ ilocalsym( 8, 4),
+ nlocalsym(12, 4),
+ iextdefsym(16, 4),
+ nextdefsym(20, 4),
+ iundefsym(24, 4),
+ nundefsym(28, 4),
+ tocoff(32, 4),
+ ntoc(36, 4),
+ modtaboff(40, 4),
+ nmodtab(44, 4),
+ extrefsymoff(48, 4),
+ nextrefsyms(52, 4),
+ indirectsymoff(56, 4),
+ nindirectsyms(60, 4),
+ extreloff(64, 4),
+ nextrel(68, 4),
+ locreloff(72, 4),
+ nlocrel(76, 4);
+
+ final int off;
+ final int sz;
+
+ dysymtab_command(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 80;
+
+ static final int LC_DYSYMTAB = 0xb;
+ }
+
+ /**
+ * relocation_info structure defines
+ */
+ enum reloc_info {
+ r_address( 0, 4),
+ r_relocinfo( 4, 4);
+
+ final int off;
+ final int sz;
+
+ reloc_info(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 8;
+
+ static final int REL_SYMNUM_MASK = 0xffffff;
+ static final int REL_SYMNUM_SHIFT = 0x0;
+ static final int REL_PCREL_MASK = 0x1;
+ static final int REL_PCREL_SHIFT = 0x18;
+ static final int REL_LENGTH_MASK = 0x3;
+ static final int REL_LENGTH_SHIFT = 0x19;
+ static final int REL_EXTERN_MASK = 0x1;
+ static final int REL_EXTERN_SHIFT = 0x1b;
+ static final int REL_TYPE_MASK = 0xf;
+ static final int REL_TYPE_SHIFT = 0x1c;
+
+ /* reloc_type_x86_64 defines */
+
+ static final int X86_64_RELOC_NONE = 0x0;
+ static final int X86_64_RELOC_BRANCH = 0x2;
+ static final int X86_64_RELOC_GOT = 0x4;
+ static final int X86_64_RELOC_GOT_LOAD = 0x3;
+ static final int X86_64_RELOC_SIGNED = 0x1;
+ static final int X86_64_RELOC_UNSIGNED = 0x0;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOByteBuffer.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOByteBuffer.java
new file mode 100644
index 000000000..a657b88ae
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOByteBuffer.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.macho;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+final class MachOByteBuffer {
+
+ static ByteBuffer allocate(int size) {
+ ByteBuffer buf = ByteBuffer.allocate(size);
+ if (MachOTargetInfo.getMachOEndian() == MachO.mach_header_64.CPU_SUBTYPE_LITTLE_ENDIAN) {
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ } else {
+ buf.order(ByteOrder.BIG_ENDIAN);
+ }
+ return (buf);
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOContainer.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOContainer.java
new file mode 100644
index 000000000..607e68ac1
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOContainer.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.macho;
+
+import java.io.File;
+import java.io.FileOutputStream;
+
+final class MachOContainer {
+
+ private final File outputFile;
+ private FileOutputStream outputStream;
+ private long fileOffset;
+
+ MachOContainer(String fileName) {
+
+ outputFile = new File(fileName);
+ if (outputFile.exists()) {
+ outputFile.delete();
+ }
+
+ try {
+ outputStream = new FileOutputStream(outputFile);
+ } catch (Exception e) {
+ System.out.println("MachOContainer: Can't create file " + fileName);
+ }
+ fileOffset = 0;
+ }
+
+ void close() {
+ try {
+ outputStream.close();
+ } catch (Exception e) {
+ System.out.println("MachOContainer: close failed");
+ }
+ }
+
+ void writeBytes(byte[] bytes) {
+ try {
+ outputStream.write(bytes);
+ } catch (Exception e) {
+ System.out.println("MachOContainer: writeBytes failed");
+ }
+ fileOffset += bytes.length;
+ }
+
+ // Write bytes to output file with up front alignment padding
+ void writeBytes(byte[] bytes, int alignment) {
+ try {
+ // Pad to alignment
+ while ((fileOffset & (alignment - 1)) != 0) {
+ outputStream.write(0);
+ fileOffset++;
+ }
+ outputStream.write(bytes);
+ } catch (Exception e) {
+ System.out.println("MachOContainer: writeBytes failed");
+ }
+ fileOffset += bytes.length;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachODySymtab.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachODySymtab.java
new file mode 100644
index 000000000..4652f9049
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachODySymtab.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.macho;
+
+import java.nio.ByteBuffer;
+
+import jdk.tools.jaotc.binformat.macho.MachO.dysymtab_command;
+
+final class MachODySymtab {
+ private final ByteBuffer dysymtab;
+
+ MachODySymtab(int nlocal, int nglobal, int nundef) {
+ dysymtab = MachOByteBuffer.allocate(dysymtab_command.totalsize);
+
+ dysymtab.putInt(dysymtab_command.cmd.off, dysymtab_command.LC_DYSYMTAB);
+ dysymtab.putInt(dysymtab_command.cmdsize.off, dysymtab_command.totalsize);
+ dysymtab.putInt(dysymtab_command.ilocalsym.off, 0);
+ dysymtab.putInt(dysymtab_command.nlocalsym.off, nlocal);
+ dysymtab.putInt(dysymtab_command.iextdefsym.off, nlocal);
+ dysymtab.putInt(dysymtab_command.nextdefsym.off, nglobal);
+ dysymtab.putInt(dysymtab_command.iundefsym.off, nlocal + nglobal);
+ dysymtab.putInt(dysymtab_command.nundefsym.off, nundef);
+ }
+
+ byte[] getArray() {
+ return dysymtab.array();
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOHeader.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOHeader.java
new file mode 100644
index 000000000..707160ba6
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOHeader.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.macho;
+
+import java.nio.ByteBuffer;
+
+import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64;
+
+final class MachOHeader {
+ private final ByteBuffer header;
+
+ MachOHeader() {
+ header = MachOByteBuffer.allocate(mach_header_64.totalsize);
+
+ header.putInt(mach_header_64.magic.off, mach_header_64.MH_MAGIC_64);
+ header.putInt(mach_header_64.cputype.off, MachOTargetInfo.getMachOArch());
+ header.putInt(mach_header_64.cpusubtype.off, MachOTargetInfo.getMachOSubArch());
+ header.putInt(mach_header_64.flags.off, 0x2000);
+ header.putInt(mach_header_64.filetype.off, mach_header_64.MH_OBJECT);
+ }
+
+ void setCmdSizes(int ncmds, int sizeofcmds) {
+ header.putInt(mach_header_64.ncmds.off, ncmds);
+ header.putInt(mach_header_64.sizeofcmds.off, sizeofcmds);
+ }
+
+ int getCmdSize() {
+ return (header.getInt(mach_header_64.sizeofcmds.off));
+ }
+
+ byte[] getArray() {
+ return header.array();
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocEntry.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocEntry.java
new file mode 100644
index 000000000..1adf01af8
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocEntry.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.macho;
+
+import java.nio.ByteBuffer;
+
+import jdk.tools.jaotc.binformat.macho.MachO.reloc_info;
+
+final class MachORelocEntry {
+ private final ByteBuffer entry;
+
+ MachORelocEntry(int offset, int symno, int pcrel, int length, int isextern, int type) {
+
+ entry = MachOByteBuffer.allocate(reloc_info.totalsize);
+
+ entry.putInt(reloc_info.r_address.off, offset);
+
+ // Encode and store the relocation entry bitfields
+ // @formatter:off
+ entry.putInt(reloc_info.r_relocinfo.off,
+ ((symno & reloc_info.REL_SYMNUM_MASK) << reloc_info.REL_SYMNUM_SHIFT) |
+ ((pcrel & reloc_info.REL_PCREL_MASK) << reloc_info.REL_PCREL_SHIFT) |
+ ((length & reloc_info.REL_LENGTH_MASK) << reloc_info.REL_LENGTH_SHIFT) |
+ ((isextern & reloc_info.REL_EXTERN_MASK) << reloc_info.REL_EXTERN_SHIFT) |
+ ((type & reloc_info.REL_TYPE_MASK) << reloc_info.REL_TYPE_SHIFT));
+ // @formatter:on
+ }
+
+ byte[] getArray() {
+ return entry.array();
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocTable.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocTable.java
new file mode 100644
index 000000000..0fafb6041
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocTable.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.macho;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+import jdk.tools.jaotc.binformat.macho.MachO.reloc_info;
+
+final class MachORelocTable {
+ private final ArrayList<ArrayList<MachORelocEntry>> relocEntries;
+ int fileOffset;
+
+ MachORelocTable(int numsects) {
+ relocEntries = new ArrayList<>(numsects);
+ for (int i = 0; i < numsects; i++) {
+ relocEntries.add(new ArrayList<MachORelocEntry>());
+ }
+ }
+
+ void createRelocationEntry(int sectindex, int offset, int symno, int pcrel, int length, int isextern, int type) {
+ MachORelocEntry entry = new MachORelocEntry(offset, symno, pcrel, length, isextern, type);
+ relocEntries.get(sectindex).add(entry);
+ }
+
+ static int getAlign() {
+ return (4);
+ }
+
+ int getNumRelocs(int sectionIndex) {
+ return relocEntries.get(sectionIndex).size();
+ }
+
+ // Return the relocation entries for a single section
+ // or null if no entries added to section
+ byte[] getRelocData(int sectionIndex) {
+ ArrayList<MachORelocEntry> entryList = relocEntries.get(sectionIndex);
+
+ if (entryList.size() == 0) {
+ return null;
+ }
+ ByteBuffer relocData = MachOByteBuffer.allocate(entryList.size() * reloc_info.totalsize);
+
+ // Copy each entry to a single ByteBuffer
+ for (int i = 0; i < entryList.size(); i++) {
+ MachORelocEntry entry = entryList.get(i);
+ relocData.put(entry.getArray());
+ }
+
+ return (relocData.array());
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSection.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSection.java
new file mode 100644
index 000000000..11bb2dacf
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSection.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.macho;
+
+import java.nio.ByteBuffer;
+
+import jdk.tools.jaotc.binformat.macho.MachO.section_64;
+
+final class MachOSection {
+ private final ByteBuffer section;
+ private final byte[] data;
+ private final boolean hasrelocations;
+
+ MachOSection(String sectName, String segName, byte[] sectData, int sectFlags, boolean hasRelocations, int align) {
+ section = MachOByteBuffer.allocate(section_64.totalsize);
+
+ // TODO: Hotspot uses long section names.
+ // They are getting truncated.
+ // Is this a problem??
+ byte[] sectNameBytes = sectName.getBytes();
+ int sectNameMax = section_64.sectname.sz < sectNameBytes.length ? section_64.sectname.sz : sectNameBytes.length;
+
+ for (int i = 0; i < sectNameMax; i++) {
+ section.put(section_64.sectname.off + i, sectNameBytes[i]);
+ }
+ byte[] segNameBytes = segName.getBytes();
+ int segNameMax = section_64.segname.sz < segNameBytes.length ? section_64.segname.sz : segNameBytes.length;
+
+ for (int i = 0; i < segNameMax; i++) {
+ section.put(section_64.segname.off + i, segNameBytes[i]);
+ }
+ section.putLong(section_64.size.off, sectData.length);
+
+ section.putInt(section_64.align.off, 31 - Integer.numberOfLeadingZeros(align));
+
+ section.putInt(section_64.flags.off, sectFlags);
+
+ data = sectData;
+
+ hasrelocations = hasRelocations;
+ }
+
+ long getSize() {
+ return section.getLong(section_64.size.off);
+ }
+
+ int getAlign() {
+ return (1 << section.getInt(section_64.align.off));
+ }
+
+ byte[] getArray() {
+ return section.array();
+ }
+
+ byte[] getDataArray() {
+ return data;
+ }
+
+ void setAddr(long addr) {
+ section.putLong(section_64.addr.off, addr);
+ }
+
+ long getAddr() {
+ return (section.getLong(section_64.addr.off));
+ }
+
+ void setOffset(int offset) {
+ section.putInt(section_64.offset.off, offset);
+ }
+
+ int getOffset() {
+ return (section.getInt(section_64.offset.off));
+ }
+
+ void setReloff(int offset) {
+ section.putInt(section_64.reloff.off, offset);
+ }
+
+ void setRelcount(int count) {
+ section.putInt(section_64.nreloc.off, count);
+ }
+
+ boolean hasRelocations() {
+ return hasrelocations;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSegment.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSegment.java
new file mode 100644
index 000000000..058343b05
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSegment.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.macho;
+
+import java.nio.ByteBuffer;
+
+import jdk.tools.jaotc.binformat.macho.MachO.segment_command_64;
+
+public class MachOSegment {
+ ByteBuffer segment;
+
+ public MachOSegment(int size, int fileoff, int filesize, int nsects) {
+ segment = MachOByteBuffer.allocate(segment_command_64.totalsize);
+
+ segment.putInt(segment_command_64.cmd.off, segment_command_64.LC_SEGMENT_64);
+ segment.putInt(segment_command_64.cmdsize.off, size);
+ segment.putInt(segment_command_64.maxprot.off, 7);
+ segment.putInt(segment_command_64.initprot.off, 7);
+ segment.putInt(segment_command_64.nsects.off, nsects);
+ segment.putInt(segment_command_64.flags.off, 0);
+ segment.putLong(segment_command_64.vmaddr.off, 0);
+ segment.putLong(segment_command_64.vmsize.off, filesize);
+ segment.putLong(segment_command_64.fileoff.off, fileoff);
+ segment.putLong(segment_command_64.filesize.off, filesize);
+ }
+
+ public byte[] getArray() {
+ return segment.array();
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymbol.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymbol.java
new file mode 100644
index 000000000..d4a3f0065
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymbol.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.macho;
+
+import java.nio.ByteBuffer;
+
+import jdk.tools.jaotc.binformat.NativeSymbol;
+import jdk.tools.jaotc.binformat.macho.MachO.nlist_64;
+
+final class MachOSymbol extends NativeSymbol {
+ private final ByteBuffer sym;
+
+ MachOSymbol(int symbolindex, int strindex, byte type, byte sectindex, long offset) {
+ super(symbolindex);
+ sym = MachOByteBuffer.allocate(nlist_64.totalsize);
+
+ sym.putInt(nlist_64.n_strx.off, strindex);
+ sym.put(nlist_64.n_type.off, type);
+ // Section indexes start at 1 but we manage the index internally
+ // as 0 relative
+ sym.put(nlist_64.n_sect.off, (byte) (sectindex + 1));
+ sym.putChar(nlist_64.n_desc.off, (char) 0);
+ sym.putLong(nlist_64.n_value.off, offset);
+ }
+
+ byte[] getArray() {
+ return sym.array();
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymtab.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymtab.java
new file mode 100644
index 000000000..c3bcff19b
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymtab.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.macho;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+import jdk.tools.jaotc.binformat.macho.MachO.nlist_64;
+import jdk.tools.jaotc.binformat.macho.MachO.symtab_command;
+
+final class MachOSymtab {
+
+ /**
+ * ByteBuffer holding the LC_SYMTAB command contents.
+ */
+ private final ByteBuffer symtabCmd;
+
+ private int symtabDataSize;
+
+ private final ArrayList<MachOSymbol> localSymbols = new ArrayList<>();
+ private final ArrayList<MachOSymbol> globalSymbols = new ArrayList<>();
+ private final ArrayList<MachOSymbol> undefSymbols = new ArrayList<>();
+
+ /**
+ * Number of symbols added.
+ */
+ private int symbolCount;
+
+ /**
+ * String holding symbol table strings.
+ */
+ private final StringBuilder strTabContent = new StringBuilder();
+
+ /**
+ * Keeps track of bytes in string table since strTabContent.length() is number of chars, not
+ * bytes.
+ */
+ private int strTabNrOfBytes = 0;
+
+ MachOSymtab() {
+ symtabCmd = MachOByteBuffer.allocate(symtab_command.totalsize);
+
+ symtabCmd.putInt(symtab_command.cmd.off, symtab_command.LC_SYMTAB);
+ symtabCmd.putInt(symtab_command.cmdsize.off, symtab_command.totalsize);
+
+ symbolCount = 0;
+
+ }
+
+ static int getAlign() {
+ return (4);
+ }
+
+ MachOSymbol addSymbolEntry(String name, byte type, byte secHdrIndex, long offset) {
+ // Get the current symbol index and append symbol name to string table.
+ int index;
+ MachOSymbol sym;
+
+ if (name.isEmpty()) {
+ index = 0;
+ strTabContent.append('\0');
+ strTabNrOfBytes += 1;
+ sym = new MachOSymbol(symbolCount, index, type, secHdrIndex, offset);
+ localSymbols.add(sym);
+ } else {
+ // We can't trust strTabContent.length() since that is
+ // chars (UTF16), keep track of bytes on our own.
+ index = strTabNrOfBytes;
+ strTabContent.append("_").append(name).append('\0');
+ // + 1 for null, + 1 for "_"
+ strTabNrOfBytes += (name.getBytes().length + 1 + 1);
+
+ sym = new MachOSymbol(symbolCount, index, type, secHdrIndex, offset);
+ switch (type) {
+ case nlist_64.N_EXT:
+ undefSymbols.add(sym);
+ break;
+ case nlist_64.N_SECT:
+ case nlist_64.N_UNDF: // null symbol
+ localSymbols.add(sym);
+ break;
+ case nlist_64.N_SECT | nlist_64.N_EXT:
+ globalSymbols.add(sym);
+ break;
+ default:
+ System.out.println("Unsupported Symbol type " + type);
+ break;
+ }
+ }
+ symbolCount++;
+ return (sym);
+ }
+
+ void setOffset(int symoff) {
+ symtabCmd.putInt(symtab_command.symoff.off, symoff);
+ }
+
+ // Update the symbol indexes once all symbols have been added.
+ // This is required since we'll be reordering the symbols in the
+ // file to be in the order of Local, global and Undefined.
+ void updateIndexes() {
+ int index = 0;
+
+ // Update the local symbol indexes
+ for (int i = 0; i < localSymbols.size(); i++) {
+ MachOSymbol sym = localSymbols.get(i);
+ sym.setIndex(index++);
+ }
+
+ // Update the global symbol indexes
+ for (int i = 0; i < globalSymbols.size(); i++) {
+ MachOSymbol sym = globalSymbols.get(i);
+ sym.setIndex(index++);
+ }
+
+ // Update the undefined symbol indexes
+ for (int i = index; i < undefSymbols.size(); i++) {
+ MachOSymbol sym = undefSymbols.get(i);
+ sym.setIndex(index++);
+ }
+ }
+
+ // Update LC_SYMTAB command fields based on the number of symbols added
+ // return the file size taken up by symbol table entries and strings
+ int calcSizes() {
+ int stroff;
+
+ stroff = symtabCmd.getInt(symtab_command.symoff.off) + (nlist_64.totalsize * symbolCount);
+ symtabCmd.putInt(symtab_command.nsyms.off, symbolCount);
+ symtabCmd.putInt(symtab_command.stroff.off, stroff);
+ symtabCmd.putInt(symtab_command.strsize.off, strTabNrOfBytes);
+ symtabDataSize = (nlist_64.totalsize * symbolCount) + strTabNrOfBytes;
+
+ return (symtabDataSize);
+ }
+
+ int getNumLocalSyms() {
+ return localSymbols.size();
+ }
+
+ int getNumGlobalSyms() {
+ return globalSymbols.size();
+ }
+
+ int getNumUndefSyms() {
+ return undefSymbols.size();
+ }
+
+ byte[] getCmdArray() {
+ return symtabCmd.array();
+ }
+
+ // Create a single byte array that contains the symbol table entries
+ // and string table
+ byte[] getDataArray() {
+ ByteBuffer symtabData = MachOByteBuffer.allocate(symtabDataSize);
+ byte[] retarray;
+
+ // Add the local symbols
+ for (int i = 0; i < localSymbols.size(); i++) {
+ MachOSymbol sym = localSymbols.get(i);
+ byte[] arr = sym.getArray();
+ symtabData.put(arr);
+ }
+ // Add the global symbols
+ for (int i = 0; i < globalSymbols.size(); i++) {
+ MachOSymbol sym = globalSymbols.get(i);
+ byte[] arr = sym.getArray();
+ symtabData.put(arr);
+ }
+ // Add the undefined symbols
+ for (int i = 0; i < undefSymbols.size(); i++) {
+ MachOSymbol sym = undefSymbols.get(i);
+ byte[] arr = sym.getArray();
+ symtabData.put(arr);
+ }
+
+ // Add the stringtable
+ byte[] strs = strTabContent.toString().getBytes();
+ symtabData.put(strs);
+
+ retarray = symtabData.array();
+
+ return (retarray);
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOTargetInfo.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOTargetInfo.java
new file mode 100644
index 000000000..628cd574f
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOTargetInfo.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.macho;
+
+import java.nio.ByteOrder;
+import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64;
+
+/**
+ * Class that abstracts MACH-O target details.
+ *
+ */
+final class MachOTargetInfo {
+ /**
+ * Target architecture and subtype.
+ */
+ private static final int arch;
+ private static final int subarch;
+
+ /**
+ * Architecture endian-ness.
+ */
+ private static final int endian = mach_header_64.CPU_SUBTYPE_LITTLE_ENDIAN;
+
+ /**
+ * Target OS string.
+ */
+ private static final String osName;
+
+ static {
+ // Find the target arch details
+ String archStr = System.getProperty("os.arch").toLowerCase();
+
+ if (ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN) {
+ System.out.println("Only Little Endian byte order supported!");
+ }
+
+ if (archStr.equals("amd64") || archStr.equals("x86_64")) {
+ arch = mach_header_64.CPU_TYPE_X86_64;
+ subarch = mach_header_64.CPU_SUBTYPE_I386_ALL;
+ } else {
+ System.out.println("Unsupported architecture " + archStr);
+ arch = mach_header_64.CPU_TYPE_ANY;
+ subarch = 0;
+ }
+
+ osName = System.getProperty("os.name").toLowerCase();
+ }
+
+ static int getMachOArch() {
+ return arch;
+ }
+
+ static int getMachOSubArch() {
+ return subarch;
+ }
+
+ static int getMachOEndian() {
+ return endian;
+ }
+
+ static String getOsName() {
+ return osName;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOVersion.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOVersion.java
new file mode 100644
index 000000000..e8092fbf0
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOVersion.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.macho;
+
+import java.nio.ByteBuffer;
+
+import jdk.tools.jaotc.binformat.macho.MachO.version_min_command;
+
+final class MachOVersion {
+ private final ByteBuffer version;
+
+ MachOVersion() {
+ version = MachOByteBuffer.allocate(version_min_command.totalsize);
+
+ version.putInt(version_min_command.cmd.off, version_min_command.LC_VERSION_MIN_MACOSX);
+ version.putInt(version_min_command.cmdsize.off, version_min_command.totalsize);
+ version.putInt(version_min_command.version.off, (10 << 16) | (10 << 8)); /* MacOSX 10.10 */
+ version.putInt(version_min_command.sdk.off, 0); /* N/A SDK */
+ }
+
+ byte[] getArray() {
+ return version.array();
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/JPECoffRelocObject.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/JPECoffRelocObject.java
new file mode 100644
index 000000000..01d6ad547
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/JPECoffRelocObject.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.pecoff;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.ByteContainer;
+import jdk.tools.jaotc.binformat.CodeContainer;
+import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
+import jdk.tools.jaotc.binformat.Relocation;
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+import jdk.tools.jaotc.binformat.Symbol;
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_FILE_HEADER;
+import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_RELOCATION;
+import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SECTION_HEADER;
+import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SYMBOL;
+
+public class JPECoffRelocObject {
+
+ private final BinaryContainer binContainer;
+
+ private final PECoffContainer pecoffContainer;
+
+ private final int sectionAlignment;
+
+ public JPECoffRelocObject(BinaryContainer binContainer, String outputFileName) {
+ this.binContainer = binContainer;
+ this.pecoffContainer = new PECoffContainer(outputFileName);
+ this.sectionAlignment = binContainer.getCodeSegmentSize();
+ }
+
+ private static PECoffSection createByteSection(ArrayList<PECoffSection> sections, String sectName, byte[] scnData,
+ boolean hasRelocs, int scnFlags, int sectAlign) {
+
+ PECoffSection sect = new PECoffSection(sectName, scnData, scnFlags, sectAlign, hasRelocs, sections.size());
+ // Add this section to our list
+ sections.add(sect);
+
+ return (sect);
+ }
+
+ private static void createByteSection(ArrayList<PECoffSection> sections, ByteContainer c, int scnFlags, int sectAlign) {
+ PECoffSection sect;
+ boolean hasRelocs = c.hasRelocations();
+ byte[] scnData = c.getByteArray();
+
+ sect = createByteSection(sections, c.getContainerName(), scnData, hasRelocs, scnFlags, sectAlign);
+
+ c.setSectionId(sect.getSectionId());
+ }
+
+ private void createCodeSection(ArrayList<PECoffSection> sections, CodeContainer c) {
+ int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_EXECUTE | IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_CODE;
+ createByteSection(sections, c, scnFlags, sectionAlignment);
+ }
+
+ private void createReadOnlySection(ArrayList<PECoffSection> sections, ReadOnlyDataContainer c) {
+ int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA;
+ createByteSection(sections, c, scnFlags, sectionAlignment);
+ }
+
+ private void createReadWriteSection(ArrayList<PECoffSection> sections, ByteContainer c) {
+ int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_WRITE;
+
+ if (c.getByteArray().length > 0) {
+ scnFlags |= IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA;
+ } else {
+ scnFlags |= IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+ }
+ createByteSection(sections, c, scnFlags, sectionAlignment);
+ }
+
+ /**
+ * Creates a PECoff relocatable object.
+ *
+ * @param relocationTable
+ * @param symbols
+ * @throws IOException throws {@code IOException} as a result of file system access failures.
+ */
+ public void createPECoffRelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException {
+ ArrayList<PECoffSection> sections = new ArrayList<>();
+
+ // Create text section
+ createCodeSection(sections, binContainer.getCodeContainer());
+ createReadOnlySection(sections, binContainer.getMetaspaceNamesContainer());
+ createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer());
+ createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer());
+ createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer());
+ createReadOnlySection(sections, binContainer.getMethodMetadataContainer());
+ createReadOnlySection(sections, binContainer.getStubsOffsetsContainer());
+ createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer());
+ createReadOnlySection(sections, binContainer.getCodeSegmentsContainer());
+ createReadOnlySection(sections, binContainer.getConstantDataContainer());
+ createReadOnlySection(sections, binContainer.getConfigContainer());
+ createReadWriteSection(sections, binContainer.getKlassesGotContainer());
+ createReadWriteSection(sections, binContainer.getCountersGotContainer());
+ createReadWriteSection(sections, binContainer.getMetadataGotContainer());
+ createReadWriteSection(sections, binContainer.getMethodStateContainer());
+ createReadWriteSection(sections, binContainer.getOopGotContainer());
+ createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer());
+
+ // Allocate PECoff Header
+ PECoffHeader header = new PECoffHeader();
+
+ // Get PECoff symbol data from BinaryContainer object's symbol tables
+ PECoffSymtab symtab = createPECoffSymbolTables(symbols);
+
+ // Add Linker Directives Section
+ int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_INFO | IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_REMOVE;
+ createByteSection(sections, ".drectve", symtab.getDirectiveArray(), false, scnFlags, 1 /*
+ * 1
+ * byte
+ * alignment
+ */);
+
+ // Create the Relocation Tables
+ PECoffRelocTable pecoffRelocs = createPECoffRelocTable(sections, relocationTable);
+
+ // File Output Order
+ //
+ // HEADER (Need address of Symbol Table + symbol count)
+ // SECTIONS (Need pointer to Section Data, Relocation Table)
+ // DIRECTIVES
+ // SYMBOL TABLE
+ // SYMBOLS
+ // SECTION DATA
+ // RELOCATION TABLE
+
+ // Calculate Offset for Symbol table
+ int fileOffset = IMAGE_FILE_HEADER.totalsize +
+ (IMAGE_SECTION_HEADER.totalsize * sections.size());
+
+ // Update Header fields
+ header.setSectionCount(sections.size());
+ header.setSymbolCount(symtab.getSymtabCount());
+ header.setSymbolOff(fileOffset);
+
+ // Calculate file offset for first section
+ fileOffset += ((symtab.getSymtabCount() * IMAGE_SYMBOL.totalsize) +
+ symtab.getStrtabSize());
+ // And round it up
+ fileOffset = (fileOffset + (sections.get(0).getDataAlign() - 1)) &
+ ~((sections.get(0).getDataAlign() - 1));
+
+ // Calc file offsets for section data
+ for (int i = 0; i < sections.size(); i++) {
+ PECoffSection sect = sections.get(i);
+ fileOffset = (fileOffset + (sect.getDataAlign() - 1)) &
+ ~((sect.getDataAlign() - 1));
+ sect.setOffset(fileOffset);
+ fileOffset += sect.getSize();
+ }
+
+ // Update relocation sizing information in each section
+ for (int i = 0; i < sections.size(); i++) {
+ PECoffSection sect = sections.get(i);
+ if (sect.hasRelocations()) {
+ int nreloc = pecoffRelocs.getNumRelocs(i);
+ sect.setReloff(fileOffset);
+ sect.setRelcount(nreloc);
+ // extended relocations add an addition entry
+ if (nreloc > 0xFFFF) {
+ nreloc++;
+ }
+ fileOffset += (nreloc * IMAGE_RELOCATION.totalsize);
+ }
+ }
+
+ // Write out the Header
+ pecoffContainer.writeBytes(header.getArray());
+
+ // Write out the section table
+ for (int i = 0; i < sections.size(); i++) {
+ PECoffSection sect = sections.get(i);
+ pecoffContainer.writeBytes(sect.getArray(), PECoffSection.getShdrAlign());
+ }
+
+ // Write out the symbol table and string table
+ pecoffContainer.writeBytes(symtab.getSymtabArray(), 4);
+ pecoffContainer.writeBytes(symtab.getStrtabArray(), 1);
+
+ // Write out each section contents
+ for (int i = 0; i < sections.size(); i++) {
+ PECoffSection sect = sections.get(i);
+ pecoffContainer.writeBytes(sect.getDataArray(), sect.getDataAlign());
+ }
+
+ // Write out Relocation Tables
+ for (int i = 0; i < sections.size(); i++) {
+ if (pecoffRelocs.getNumRelocs(i) > 0) {
+ pecoffContainer.writeBytes(pecoffRelocs.getRelocData(i));
+ }
+ }
+ pecoffContainer.close();
+ }
+
+ /**
+ * Construct PECoff symbol data from BinaryContainer object's symbol tables. Both dynamic PECoff
+ * symbol table and PECoff symbol table are created from BinaryContainer's symbol info.
+ *
+ * @param symbols
+ */
+ private static PECoffSymtab createPECoffSymbolTables(Collection<Symbol> symbols) {
+ PECoffSymtab symtab = new PECoffSymtab();
+
+ // First, create the initial null symbol. This is a local symbol.
+ // symtab.addSymbolEntry("", (byte)0, (byte)0, (byte)0, 0, 0);
+
+ // Now create PECoff symbol entries for all symbols.
+ for (Symbol symbol : symbols) {
+ // Get the index of section this symbol is defined in.
+ int secHdrIndex = symbol.getSection().getSectionId();
+ PECoffSymbol pecoffSymbol = symtab.addSymbolEntry(symbol.getName(), getPECoffTypeOf(symbol), getPECoffClassOf(symbol), (byte) secHdrIndex, symbol.getOffset());
+ symbol.setNativeSymbol(pecoffSymbol);
+ }
+ return (symtab);
+ }
+
+ private static byte getPECoffTypeOf(Symbol sym) {
+ Kind kind = sym.getKind();
+ if (kind == Symbol.Kind.NATIVE_FUNCTION || kind == Symbol.Kind.JAVA_FUNCTION) {
+ return IMAGE_SYMBOL.IMAGE_SYM_DTYPE_FUNCTION;
+ }
+ return IMAGE_SYMBOL.IMAGE_SYM_DTYPE_NONE;
+ }
+
+ private static byte getPECoffClassOf(Symbol sym) {
+ Binding binding = sym.getBinding();
+ if (binding == Symbol.Binding.GLOBAL) {
+ return IMAGE_SYMBOL.IMAGE_SYM_CLASS_EXTERNAL;
+ }
+ return IMAGE_SYMBOL.IMAGE_SYM_CLASS_STATIC;
+ }
+
+ /**
+ * Construct a PECoff relocation table from BinaryContainer object's relocation tables.
+ *
+ * @param sections
+ * @param relocationTable
+ */
+ private PECoffRelocTable createPECoffRelocTable(ArrayList<PECoffSection> sections, Map<Symbol, List<Relocation>> relocationTable) {
+
+ PECoffRelocTable pecoffRelocTable = new PECoffRelocTable(sections.size());
+ /*
+ * For each of the symbols with associated relocation records, create a PECoff relocation
+ * entry.
+ */
+ for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) {
+ List<Relocation> relocs = entry.getValue();
+ Symbol symbol = entry.getKey();
+
+ for (Relocation reloc : relocs) {
+ createRelocation(symbol, reloc, pecoffRelocTable);
+ }
+ }
+
+ for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) {
+ createRelocation(entry.getKey(), entry.getValue(), pecoffRelocTable);
+ }
+
+ return (pecoffRelocTable);
+ }
+
+ private static void createRelocation(Symbol symbol, Relocation reloc, PECoffRelocTable pecoffRelocTable) {
+ RelocType relocType = reloc.getType();
+
+ int pecoffRelocType = getPECoffRelocationType(relocType);
+ PECoffSymbol sym = (PECoffSymbol) symbol.getNativeSymbol();
+ int symno = sym.getIndex();
+ int sectindex = reloc.getSection().getSectionId();
+ int offset = reloc.getOffset();
+ int addend = 0;
+
+ switch (relocType) {
+ case JAVA_CALL_DIRECT:
+ case STUB_CALL_DIRECT:
+ case FOREIGN_CALL_INDIRECT_GOT: {
+ // Create relocation entry
+ addend = -4; // Size in bytes of the patch location
+ // Relocation should be applied at the location after call operand
+ offset = offset + reloc.getSize() + addend;
+ break;
+ }
+ case JAVA_CALL_INDIRECT: {
+ // Do nothing.
+ return;
+ }
+ case METASPACE_GOT_REFERENCE:
+ case EXTERNAL_PLT_TO_GOT: {
+ addend = -4; // Size of 32-bit address of the GOT
+ /*
+ * Relocation should be applied before the test instruction to the move instruction.
+ * reloc.getOffset() points to the test instruction after the instruction that loads
+ * the address of polling page. So set the offset appropriately.
+ */
+ offset = offset + addend;
+ break;
+ }
+ case EXTERNAL_GOT_TO_PLT: {
+ // this is load time relocations
+ break;
+ }
+ default:
+ throw new InternalError("Unhandled relocation type: " + relocType);
+ }
+ pecoffRelocTable.createRelocationEntry(sectindex, offset, symno, pecoffRelocType);
+ }
+
+ // Return IMAGE_RELOCATION Type based on relocType
+ private static int getPECoffRelocationType(RelocType relocType) {
+ int pecoffRelocType = 0; // R_<ARCH>_NONE if #define'd to 0 for all values of ARCH
+ switch (PECoffTargetInfo.getPECoffArch()) {
+ case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64:
+ if (relocType == RelocType.JAVA_CALL_DIRECT ||
+ relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
+ pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
+ } else if (relocType == RelocType.STUB_CALL_DIRECT) {
+ pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
+ } else if (relocType == RelocType.JAVA_CALL_INDIRECT) {
+ pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ABSOLUTE;
+ } else if (relocType == RelocType.METASPACE_GOT_REFERENCE ||
+ relocType == RelocType.EXTERNAL_PLT_TO_GOT) {
+ pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
+ } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT) {
+ pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ADDR64;
+ } else {
+ assert false : "Unhandled relocation type: " + relocType;
+ }
+ break;
+ default:
+ System.out.println("Relocation Type mapping: Unhandled architecture");
+ }
+ return pecoffRelocType;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoff.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoff.java
new file mode 100644
index 000000000..1521c2e20
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoff.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.pecoff;
+
+/**
+ *
+ * Support for the creation of Coff files. Current support is limited to 64 bit x86_64.
+ *
+ */
+
+final class PECoff {
+ //@formatter:off
+ /**
+ * IMAGE_FILE_HEADER structure defines.
+ */
+ enum IMAGE_FILE_HEADER {
+ Machine(0, 2),
+ NumberOfSections(2, 2),
+ TimeDateStamp(4, 4),
+ PointerToSymbolTable(8, 4),
+ NumberOfSymbols(12, 4),
+ SizeOfOptionalHeader(16, 2),
+ Characteristics(18, 2);
+
+ final int off;
+ final int sz;
+
+ IMAGE_FILE_HEADER(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 20;
+
+ /**
+ * IMAGE_FILE_HEADER defines
+ */
+
+ /**
+ * Machine.
+ */
+ static final char IMAGE_FILE_MACHINE_UNKNOWN = 0x0;
+ static final char IMAGE_FILE_MACHINE_AMD64 = 0x8664;
+
+ }
+
+ /**
+ * IMAGE_SECTION_HEADER structure defines.
+ */
+ enum IMAGE_SECTION_HEADER {
+ Name(0, 8),
+ PhysicalAddress(8, 4),
+ VirtualSize(8, 4),
+ VirtualAddress(12, 4),
+ SizeOfRawData(16, 4),
+ PointerToRawData(20, 4),
+ PointerToRelocations(24, 4),
+ PointerToLinenumbers(28, 4),
+ NumberOfRelocations(32, 2),
+ NumberOfLinenumbers(34, 2),
+ Characteristics(36, 4);
+
+ final int off;
+ final int sz;
+
+ IMAGE_SECTION_HEADER(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 40;
+
+ /**
+ * IMAGE_SECTION_HEADER defines
+ */
+
+ /**
+ * Characteristics.
+ */
+ static final int IMAGE_SCN_CNT_CODE = 0x20;
+ static final int IMAGE_SCN_CNT_INITIALIZED_DATA = 0x40;
+ static final int IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x80;
+ static final int IMAGE_SCN_LNK_COMDAT = 0x1000;
+ static final int IMAGE_SCN_LNK_INFO = 0x200;
+ static final int IMAGE_SCN_LNK_REMOVE = 0x800;
+
+ static final int IMAGE_SCN_ALIGN_1BYTES = 0x100000;
+ static final int IMAGE_SCN_ALIGN_2BYTES = 0x200000;
+ static final int IMAGE_SCN_ALIGN_4BYTES = 0x300000;
+ static final int IMAGE_SCN_ALIGN_8BYTES = 0x400000;
+ static final int IMAGE_SCN_ALIGN_16BYTES = 0x500000;
+ static final int IMAGE_SCN_ALIGN_32BYTES = 0x600000;
+ static final int IMAGE_SCN_ALIGN_64BYTES = 0x700000;
+ static final int IMAGE_SCN_ALIGN_128BYTES = 0x800000;
+ static final int IMAGE_SCN_ALIGN_256BYTES = 0x900000;
+ static final int IMAGE_SCN_ALIGN_512BYTES = 0xa00000;
+ static final int IMAGE_SCN_ALIGN_1024BYTES = 0xb00000;
+ static final int IMAGE_SCN_ALIGN_MASK = 0xf00000;
+ static final int IMAGE_SCN_ALIGN_SHIFT = 20;
+
+ static final int IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000;
+
+ static final int IMAGE_SCN_MEM_SHARED = 0x10000000;
+ static final int IMAGE_SCN_MEM_EXECUTE = 0x20000000;
+ static final int IMAGE_SCN_MEM_READ = 0x40000000;
+ static final int IMAGE_SCN_MEM_WRITE = 0x80000000;
+
+ }
+
+ /**
+ * Symbol table entry definitions.
+ *
+ * IMAGE_SYMBOL structure defines
+ */
+ enum IMAGE_SYMBOL {
+ ShortName(0, 8),
+ Short(0, 4),
+ Long(4, 4),
+ Value(8, 4),
+ SectionNumber(12, 2),
+ Type(14, 2),
+ StorageClass(16, 1),
+ NumberOfAuxSymbols(17, 1);
+
+ final int off;
+ final int sz;
+
+ IMAGE_SYMBOL(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 18;
+
+ /**
+ * Type.
+ */
+ static final int IMAGE_SYM_DTYPE_NONE = 0x0;
+ static final int IMAGE_SYM_DTYPE_FUNCTION = 0x20;
+
+ /**
+ * StorageClass.
+ */
+ static final int IMAGE_SYM_CLASS_NULL = 0x0;
+ static final int IMAGE_SYM_CLASS_EXTERNAL = 0x2;
+ static final int IMAGE_SYM_CLASS_STATIC = 0x3;
+ static final int IMAGE_SYM_CLASS_LABEL = 0x6;
+
+ }
+
+ /**
+ * IMAGE_RELOCATION structure defines.
+ */
+ enum IMAGE_RELOCATION {
+ VirtualAddress(0, 4),
+ SymbolTableIndex(4, 4),
+ Type(8, 2);
+
+ final int off;
+ final int sz;
+
+ IMAGE_RELOCATION(int offset, int size) {
+ this.off = offset;
+ this.sz = size;
+ }
+
+ static int totalsize = 10;
+
+ /**
+ * Relocation types.
+ */
+ static final int IMAGE_REL_AMD64_ABSOLUTE = 0x0;
+ static final int IMAGE_REL_AMD64_ADDR32 = 0x2;
+ static final int IMAGE_REL_AMD64_ADDR64 = 0x1;
+ static final int IMAGE_REL_AMD64_REL32 = 0x4;
+ static final int IMAGE_REL_AMD64_REL32_1 = 0x5;
+ static final int IMAGE_REL_AMD64_REL32_2 = 0x6;
+ static final int IMAGE_REL_AMD64_REL32_3 = 0x7;
+ static final int IMAGE_REL_AMD64_REL32_4 = 0x8;
+ static final int IMAGE_REL_AMD64_REL32_5 = 0x9;
+
+ }
+ //@formatter:on
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffByteBuffer.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffByteBuffer.java
new file mode 100644
index 000000000..835642314
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffByteBuffer.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.pecoff;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+final class PECoffByteBuffer {
+
+ static ByteBuffer allocate(int size) {
+ ByteBuffer buf = ByteBuffer.allocate(size);
+ // Only support Little Endian on Windows
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ return (buf);
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffContainer.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffContainer.java
new file mode 100644
index 000000000..21ad80270
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffContainer.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.pecoff;
+
+import java.io.File;
+import java.io.FileOutputStream;
+
+final class PECoffContainer {
+
+ private final File outputFile;
+ private FileOutputStream outputStream;
+ private long fileOffset;
+
+ PECoffContainer(String fileName) {
+
+ outputFile = new File(fileName);
+ if (outputFile.exists()) {
+ outputFile.delete();
+ }
+
+ try {
+ outputStream = new FileOutputStream(outputFile);
+ } catch (Exception e) {
+ System.out.println("PECoffContainer: Can't create file " + fileName);
+ }
+ fileOffset = 0;
+ }
+
+ void close() {
+ try {
+ outputStream.close();
+ } catch (Exception e) {
+ System.out.println("PECoffContainer: close failed");
+ }
+ }
+
+ void writeBytes(byte[] bytes) {
+ if (bytes == null) {
+ return;
+ }
+ try {
+ outputStream.write(bytes);
+ } catch (Exception e) {
+ System.out.println("PECoffContainer: writeBytes failed");
+ }
+ fileOffset += bytes.length;
+ }
+
+ // Write bytes to output file with up front alignment padding
+ void writeBytes(byte[] bytes, int alignment) {
+ if (bytes == null) {
+ return;
+ }
+ try {
+ // Pad to alignment
+ while ((fileOffset & (alignment - 1)) != 0) {
+ outputStream.write(0);
+ fileOffset++;
+ }
+ outputStream.write(bytes);
+ } catch (Exception e) {
+ System.out.println("PECoffContainer: writeBytes failed");
+ }
+ fileOffset += bytes.length;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffHeader.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffHeader.java
new file mode 100644
index 000000000..411fcb47e
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffHeader.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.pecoff;
+
+import java.nio.ByteBuffer;
+
+import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_FILE_HEADER;
+
+final class PECoffHeader {
+ private final ByteBuffer header;
+
+ PECoffHeader() {
+ header = PECoffByteBuffer.allocate(IMAGE_FILE_HEADER.totalsize);
+
+ header.putChar(IMAGE_FILE_HEADER.Machine.off, IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64);
+ header.putInt(IMAGE_FILE_HEADER.TimeDateStamp.off, (int) (System.currentTimeMillis() / 1000));
+ header.putInt(IMAGE_FILE_HEADER.PointerToSymbolTable.off, 0);
+ header.putInt(IMAGE_FILE_HEADER.NumberOfSymbols.off, 0);
+ header.putChar(IMAGE_FILE_HEADER.SizeOfOptionalHeader.off, (char) 0);
+ header.putChar(IMAGE_FILE_HEADER.Characteristics.off, (char) 0);
+
+ }
+
+ // Update header with the number of total sections
+ void setSectionCount(int count) {
+ header.putChar(IMAGE_FILE_HEADER.NumberOfSections.off, (char) count);
+ }
+
+ // Update header with the number of total symbols
+ void setSymbolCount(int count) {
+ header.putInt(IMAGE_FILE_HEADER.NumberOfSymbols.off, count);
+ }
+
+ // Update header with the offset of symbol table
+ void setSymbolOff(int offset) {
+ header.putInt(IMAGE_FILE_HEADER.PointerToSymbolTable.off, offset);
+ }
+
+ byte[] getArray() {
+ return header.array();
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocEntry.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocEntry.java
new file mode 100644
index 000000000..cc4236de5
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocEntry.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.pecoff;
+
+import java.nio.ByteBuffer;
+
+import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_RELOCATION;
+
+final class PECoffRelocEntry {
+ private final ByteBuffer entry;
+
+ PECoffRelocEntry(int offset, int symno, int type) {
+
+ entry = PECoffByteBuffer.allocate(IMAGE_RELOCATION.totalsize);
+
+ entry.putInt(IMAGE_RELOCATION.VirtualAddress.off, offset);
+ entry.putInt(IMAGE_RELOCATION.SymbolTableIndex.off, symno);
+ entry.putChar(IMAGE_RELOCATION.Type.off, (char) type);
+ }
+
+ byte[] getArray() {
+ return entry.array();
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocTable.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocTable.java
new file mode 100644
index 000000000..b825c70dd
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocTable.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.pecoff;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_RELOCATION;
+
+final class PECoffRelocTable {
+ ArrayList<ArrayList<PECoffRelocEntry>> relocEntries;
+
+ PECoffRelocTable(int numsects) {
+ relocEntries = new ArrayList<>(numsects);
+ for (int i = 0; i < numsects; i++) {
+ relocEntries.add(new ArrayList<PECoffRelocEntry>());
+ }
+ }
+
+ void createRelocationEntry(int sectindex, int offset, int symno, int type) {
+ PECoffRelocEntry entry = new PECoffRelocEntry(offset, symno, type);
+ relocEntries.get(sectindex).add(entry);
+ }
+
+ static int getAlign() {
+ return (4);
+ }
+
+ int getNumRelocs(int sectionIndex) {
+ return relocEntries.get(sectionIndex).size();
+ }
+
+ // Return the relocation entries for a single section
+ // or null if no entries added to section
+ byte[] getRelocData(int sectionIndex) {
+ ArrayList<PECoffRelocEntry> entryList = relocEntries.get(sectionIndex);
+ int entryCount = entryList.size();
+ int allocCount = entryCount;
+
+ if (entryCount == 0) {
+ return null;
+ }
+ if (entryCount > 0xFFFF) {
+ allocCount++;
+ }
+ ByteBuffer relocData = PECoffByteBuffer.allocate(allocCount * IMAGE_RELOCATION.totalsize);
+
+ // If number of relocs exceeds 65K, add the real size
+ // in a dummy first reloc entry
+ if (entryCount > 0xFFFF) {
+ PECoffRelocEntry entry = new PECoffRelocEntry(allocCount, 0, 0);
+ relocData.put(entry.getArray());
+ }
+
+ // Copy each entry to a single ByteBuffer
+ for (int i = 0; i < entryCount; i++) {
+ PECoffRelocEntry entry = entryList.get(i);
+ relocData.put(entry.getArray());
+ }
+
+ return (relocData.array());
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSection.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSection.java
new file mode 100644
index 000000000..3d3f99a26
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSection.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.pecoff;
+
+import java.nio.ByteBuffer;
+
+import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SECTION_HEADER;
+
+final class PECoffSection {
+ private final ByteBuffer section;
+ private final byte[] data;
+ private final boolean hasrelocations;
+ private final int sectionIndex;
+ private final int align;
+
+ PECoffSection(String sectName, byte[] sectData0, int sectFlags0, int sectAlign, boolean hasRelocations, int sectIndex) {
+
+ section = PECoffByteBuffer.allocate(IMAGE_SECTION_HEADER.totalsize);
+
+ // If .oop.got section is empty, VM exits since .oop.got
+ // symbol ends up as external forwarded reference.
+ byte[] sectData = sectData0;
+ if (sectData0.length == 0) {
+ sectData = new byte[8];
+ }
+
+ // Copy only Max allowed bytes to Section Entry
+ byte[] name = sectName.getBytes();
+ int max = name.length <= IMAGE_SECTION_HEADER.Name.sz ? name.length : IMAGE_SECTION_HEADER.Name.sz;
+
+ assert !(sectAlign < 1 || sectAlign > 1024 || (sectAlign & (sectAlign - 1)) != 0) : "section alignment is not valid: " + sectAlign;
+ align = sectAlign;
+
+ // Using 32 because IMAGE_SCN_ALIGN_*BYTES is value + 1
+ int sectAlignBits = (32 - Integer.numberOfLeadingZeros(align)) << IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_SHIFT;
+ // Clear and set alignment bits
+ int sectFlags = (sectFlags0 & ~IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_MASK) | (sectAlignBits & IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_MASK);
+
+ section.put(name, IMAGE_SECTION_HEADER.Name.off, max);
+
+ section.putInt(IMAGE_SECTION_HEADER.VirtualSize.off, 0);
+ section.putInt(IMAGE_SECTION_HEADER.VirtualAddress.off, 0);
+ section.putInt(IMAGE_SECTION_HEADER.SizeOfRawData.off, sectData.length);
+ section.putInt(IMAGE_SECTION_HEADER.PointerToLinenumbers.off, 0);
+ section.putChar(IMAGE_SECTION_HEADER.NumberOfLinenumbers.off, (char) 0);
+
+ section.putInt(IMAGE_SECTION_HEADER.Characteristics.off, sectFlags);
+
+ data = sectData;
+ hasrelocations = hasRelocations;
+ sectionIndex = sectIndex;
+ }
+
+ long getSize() {
+ return section.getInt(IMAGE_SECTION_HEADER.SizeOfRawData.off);
+ }
+
+ int getDataAlign() {
+ return (align);
+ }
+
+ // Alignment requirements for the IMAGE_SECTION_HEADER structures
+ static int getShdrAlign() {
+ return (4);
+ }
+
+ byte[] getArray() {
+ return section.array();
+ }
+
+ byte[] getDataArray() {
+ return data;
+ }
+
+ void setOffset(long offset) {
+ section.putInt(IMAGE_SECTION_HEADER.PointerToRawData.off, (int) offset);
+ }
+
+ long getOffset() {
+ return (section.getInt(IMAGE_SECTION_HEADER.PointerToRawData.off));
+ }
+
+ void setReloff(int offset) {
+ section.putInt(IMAGE_SECTION_HEADER.PointerToRelocations.off, offset);
+ }
+
+ void setRelcount(int count) {
+ // If the number of relocs is larger than 65K, then set
+ // the overflow bit. The real count will be written to
+ // the first reloc entry for this section.
+ if (count > 0xFFFF) {
+ int flags;
+ section.putChar(IMAGE_SECTION_HEADER.NumberOfRelocations.off, (char) 0xFFFF);
+ flags = section.getInt(IMAGE_SECTION_HEADER.Characteristics.off);
+ flags |= IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_NRELOC_OVFL;
+ section.putInt(IMAGE_SECTION_HEADER.Characteristics.off, flags);
+ } else {
+ section.putChar(IMAGE_SECTION_HEADER.NumberOfRelocations.off, (char) count);
+ }
+ }
+
+ boolean hasRelocations() {
+ return hasrelocations;
+ }
+
+ int getSectionId() {
+ return sectionIndex;
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymbol.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymbol.java
new file mode 100644
index 000000000..105164731
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymbol.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.pecoff;
+
+import java.nio.ByteBuffer;
+
+import jdk.tools.jaotc.binformat.NativeSymbol;
+import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SYMBOL;
+
+final class PECoffSymbol extends NativeSymbol {
+ private final ByteBuffer sym;
+
+ PECoffSymbol(int symbolindex, int strindex, byte type, byte storageclass, byte sectindex, long offset) {
+ super(symbolindex);
+ sym = PECoffByteBuffer.allocate(IMAGE_SYMBOL.totalsize);
+
+ // We don't use short names
+ sym.putInt(IMAGE_SYMBOL.Short.off, 0);
+
+ sym.putInt(IMAGE_SYMBOL.Long.off, strindex);
+ sym.putInt(IMAGE_SYMBOL.Value.off, (int) offset);
+
+ // Section indexes start at 1 but we manage the index internally
+ // as 0 relative except in this structure
+ sym.putChar(IMAGE_SYMBOL.SectionNumber.off, (char) (sectindex + 1));
+
+ sym.putChar(IMAGE_SYMBOL.Type.off, (char) type);
+ sym.put(IMAGE_SYMBOL.StorageClass.off, storageclass);
+ sym.put(IMAGE_SYMBOL.NumberOfAuxSymbols.off, (byte) 0);
+ }
+
+ byte[] getArray() {
+ return sym.array();
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymtab.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymtab.java
new file mode 100644
index 000000000..1e8b3ec3f
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymtab.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.pecoff;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+
+import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SYMBOL;
+
+final class PECoffSymtab {
+ ArrayList<PECoffSymbol> symbols = new ArrayList<>();
+
+ /**
+ * Number of symbols added.
+ */
+ private int symbolCount;
+
+ /**
+ * String holding symbol table strings.
+ */
+ private final StringBuilder strTabContent;
+
+ /**
+ * Keeps track of bytes in string table since strTabContent.length() is number of chars, not
+ * bytes.
+ */
+ private int strTabNrOfBytes;
+
+ /**
+ * String holding Linker Directives.
+ */
+ private final StringBuilder directives;
+
+ PECoffSymtab() {
+ symbolCount = 0;
+ strTabContent = new StringBuilder();
+ directives = new StringBuilder();
+
+ // The first 4 bytes of the string table contain
+ // the length of the table (including this length field).
+ strTabNrOfBytes = 4;
+
+ // Make room for the 4 byte length field
+ strTabContent.append('\0').append('\0').append('\0').append('\0');
+
+ // Linker Directives start with 3 spaces to signify ANSI
+ directives.append(" ");
+ }
+
+ PECoffSymbol addSymbolEntry(String name, byte type, byte storageclass, byte secHdrIndex, long offset) {
+ // Get the current symbol index and append symbol name to string table.
+ int index;
+ PECoffSymbol sym;
+
+ if (name.isEmpty()) {
+ index = 0;
+ strTabContent.append('\0');
+ strTabNrOfBytes += 1;
+ sym = new PECoffSymbol(symbolCount, index, type, storageclass, secHdrIndex, offset);
+ symbols.add(sym);
+ } else {
+ int nameSize = name.getBytes().length;
+
+ // We can't trust strTabContent.length() since that is
+ // chars (UTF16), keep track of bytes on our own.
+ index = strTabNrOfBytes;
+ // strTabContent.append('_').append(name).append('\0');
+ strTabContent.append(name).append('\0');
+ strTabNrOfBytes += (nameSize + 1);
+
+ sym = new PECoffSymbol(symbolCount, index, type, storageclass, secHdrIndex, offset);
+ symbols.add(sym);
+ if (storageclass == IMAGE_SYMBOL.IMAGE_SYM_CLASS_EXTERNAL) {
+ addDirective(name, type);
+ }
+ }
+ symbolCount++;
+ return (sym);
+ }
+
+ private void addDirective(String name, byte type) {
+ directives.append("/EXPORT:" + name);
+ if (type != IMAGE_SYMBOL.IMAGE_SYM_DTYPE_FUNCTION) {
+ directives.append(",DATA");
+ }
+ directives.append(" ");
+ }
+
+ int getSymtabCount() {
+ return symbolCount;
+ }
+
+ int getStrtabSize() {
+ return strTabNrOfBytes;
+ }
+
+ // Return a byte array that contains the symbol table entries
+ byte[] getSymtabArray() {
+ ByteBuffer symtabData = PECoffByteBuffer.allocate(symbolCount * IMAGE_SYMBOL.totalsize);
+ symtabData.order(ByteOrder.LITTLE_ENDIAN);
+
+ // copy all symbols
+ for (int i = 0; i < symbolCount; i++) {
+ PECoffSymbol sym = symbols.get(i);
+ byte[] arr = sym.getArray();
+ symtabData.put(arr);
+ }
+ return (symtabData.array());
+ }
+
+ // Return the string table array
+ byte[] getStrtabArray() {
+ byte[] strs = strTabContent.toString().getBytes();
+
+ // Update the size of the string table
+ ByteBuffer buff = ByteBuffer.wrap(strs);
+ buff.order(ByteOrder.LITTLE_ENDIAN);
+ buff.putInt(0, strTabNrOfBytes);
+
+ return (strs);
+ }
+
+ byte[] getDirectiveArray() {
+ return (directives.toString().getBytes());
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffTargetInfo.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffTargetInfo.java
new file mode 100644
index 000000000..44288593c
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffTargetInfo.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.binformat.pecoff;
+
+import java.nio.ByteOrder;
+import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_FILE_HEADER;
+
+/**
+ * Class that abstracts MACH-O target details.
+ *
+ */
+final class PECoffTargetInfo {
+ /**
+ * Target architecture.
+ */
+ private static final char arch;
+
+ /**
+ * Target OS string.
+ */
+ private static String osName;
+
+ static {
+ // Find the target arch details
+ String archStr = System.getProperty("os.arch").toLowerCase();
+ if (ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN) {
+ System.out.println("Only Little Endian byte order supported!");
+ }
+
+ if (archStr.equals("amd64") || archStr.equals("x86_64")) {
+ arch = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64;
+ } else {
+ System.out.println("Unsupported architecture " + archStr);
+ arch = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_UNKNOWN;
+ }
+
+ osName = System.getProperty("os.name").toLowerCase();
+ if (!osName.contains("windows")) {
+ System.out.println("Unsupported Operating System " + osName);
+ osName = "Unknown";
+ }
+ }
+
+ static char getPECoffArch() {
+ return arch;
+ }
+
+ static String getOsName() {
+ return osName;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/HelloWorld.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/HelloWorld.java
new file mode 100644
index 000000000..ffedd0dee
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/HelloWorld.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package jdk.tools.jaotc.test;
+
+public class HelloWorld {
+ public static void main(String[] args) {
+ System.out.println("Hello, world!");
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/NativeOrderOutputStreamTest.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/NativeOrderOutputStreamTest.java
new file mode 100644
index 000000000..13ee4b1b2
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/NativeOrderOutputStreamTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @requires vm.aot
+ * @modules jdk.aot/jdk.tools.jaotc.utils
+ * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.tools.jaotc.test.NativeOrderOutputStreamTest
+ */
+
+
+
+package jdk.tools.jaotc.test;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.tools.jaotc.utils.NativeOrderOutputStream;
+
+public class NativeOrderOutputStreamTest {
+
+ @Test
+ public void shouldAdd4BytesForInt() {
+ NativeOrderOutputStream target = new NativeOrderOutputStream();
+ target.putInt(5);
+ Assert.assertEquals(4, target.position());
+ }
+
+ @Test
+ public void shouldAdd8BytesForLong() {
+ NativeOrderOutputStream target = new NativeOrderOutputStream();
+ target.putLong(8);
+ Assert.assertEquals(8, target.position());
+ }
+
+ @Test
+ public void shouldHaveCorrectSizeBeforePatch() {
+ NativeOrderOutputStream target = new NativeOrderOutputStream();
+ target.patchableInt();
+ Assert.assertEquals(4, target.position());
+ }
+
+ @Test
+ public void shouldHaveCorrectSizeAfterPatch() {
+ NativeOrderOutputStream target = new NativeOrderOutputStream();
+ NativeOrderOutputStream.PatchableInt patchableInt = target.patchableInt();
+ patchableInt.set(12);
+ Assert.assertEquals(4, target.position());
+ }
+
+ @Test
+ public void shouldSetCorrectValueInPatch() {
+ NativeOrderOutputStream target = new NativeOrderOutputStream();
+ NativeOrderOutputStream.PatchableInt patchableInt = target.patchableInt();
+ patchableInt.set(42);
+ Assert.assertEquals(42, getInt(target, 0));
+ }
+
+ private static int getInt(NativeOrderOutputStream target, int pos) {
+ ByteBuffer buffer = ByteBuffer.wrap(target.array());
+ buffer.order(ByteOrder.nativeOrder());
+ return buffer.getInt(pos);
+ }
+
+ @Test
+ public void shouldPutArrayCorrectly() {
+ NativeOrderOutputStream target = new NativeOrderOutputStream();
+ target.put(new byte[]{42, 5, 43, 44});
+ Assert.assertEquals(4, target.position());
+ Assert.assertEquals(42, target.array()[0]);
+ Assert.assertEquals(4, target.position());
+ }
+
+ @Test
+ public void shouldOnlyPatchSlot() {
+ NativeOrderOutputStream target = new NativeOrderOutputStream();
+ NativeOrderOutputStream.PatchableInt patchableInt = target.patchableInt();
+ target.putInt(7);
+ patchableInt.set(39);
+ Assert.assertEquals(39, getInt(target, 0));
+ Assert.assertEquals(7, getInt(target, 4));
+ }
+
+ @Test
+ public void shouldBeAbleToPatchAnywhere() {
+ NativeOrderOutputStream target = new NativeOrderOutputStream();
+ target.putInt(19);
+ NativeOrderOutputStream.PatchableInt patchableInt = target.patchableInt();
+ patchableInt.set(242);
+
+ Assert.assertEquals(19, getInt(target, 0));
+ Assert.assertEquals(242, getInt(target, 4));
+ }
+
+ @Test
+ public void shouldHavePatchableAtRightOffset() {
+ NativeOrderOutputStream target = new NativeOrderOutputStream();
+ target.putInt(27);
+ Assert.assertEquals(4, target.position());
+ NativeOrderOutputStream.PatchableInt patchableInt = target.patchableInt();
+ Assert.assertEquals(4, patchableInt.position());
+ }
+
+ @Test
+ public void shouldAlign() {
+ NativeOrderOutputStream target = new NativeOrderOutputStream();
+ target.putInt(9);
+ target.align(16);
+ target.put(new byte[]{3});
+ target.align(8);
+ Assert.assertEquals(24, target.position());
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java
new file mode 100644
index 000000000..b2358dff2
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @requires vm.aot
+ * @modules jdk.aot/jdk.tools.jaotc
+ * jdk.aot/jdk.tools.jaotc.collect
+ * @run junit/othervm jdk.tools.jaotc.test.collect.ClassSearchTest
+ */
+
+
+
+package jdk.tools.jaotc.test.collect;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.tools.jaotc.LoadedClass;
+import jdk.tools.jaotc.collect.ClassSearch;
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.SearchFor;
+import jdk.tools.jaotc.collect.SearchPath;
+import jdk.tools.jaotc.collect.SourceProvider;
+
+public class ClassSearchTest {
+ @Test(expected = InternalError.class)
+ public void itShouldThrowExceptionIfNoProvidersAvailable() {
+ ClassSearch target = new ClassSearch();
+ SearchPath searchPath = new SearchPath();
+ target.search(list(new SearchFor("foo")), searchPath);
+ }
+
+ @Test
+ public void itShouldFindAProviderForEachEntry() {
+ Set<String> searched = new HashSet<>();
+ ClassSearch target = new ClassSearch();
+ target.addProvider(provider("", (name, searchPath) -> {
+ searched.add(name);
+ return new NoopSource();
+ }));
+ target.search(searchForList("foo", "bar", "foobar"), null);
+ Assert.assertEquals(hashset("foo", "bar", "foobar"), searched);
+ }
+
+ private static SourceProvider provider(String supports, BiFunction<String, SearchPath, ClassSource> fn) {
+ return new SourceProvider() {
+ @Override
+ public ClassSource findSource(String name, SearchPath searchPath) {
+ return fn.apply(name, searchPath);
+ }
+
+ @Override
+ public boolean supports(String type) {
+ return supports.equals(type);
+ }
+ };
+ }
+
+ @Test
+ public void itShouldOnlySearchSupportedProvidersForKnownType() {
+ Set<String> visited = new HashSet<>();
+ ClassSearch target = new ClassSearch();
+
+ target.addProvider(provider("jar", (name, searchPath) -> {
+ visited.add("jar");
+ return null;
+ }));
+
+ target.addProvider(provider("dir", (name, searchPath) -> {
+ visited.add("dir");
+ return null;
+ }));
+
+ try {
+ target.search(list(new SearchFor("some", "dir")), null);
+ } catch (InternalError e) {
+ // throws because no provider gives a source
+ }
+
+ Assert.assertEquals(hashset("dir"), visited);
+ }
+
+ @Test(expected = InternalError.class)
+ public void itShouldThrowErrorIfMultipleSourcesAreAvailable() {
+ ClassSearch target = new ClassSearch();
+ target.addProvider(provider("", (name, searchPath) -> consumer -> Assert.fail()));
+ target.addProvider(provider("", (name, searchPath) -> consumer -> Assert.fail()));
+
+ target.search(searchForList("somethign"), null);
+ }
+
+ @Test
+ public void itShouldSearchAllProvidersForUnknownType() {
+ Set<String> visited = new HashSet<>();
+ ClassSearch target = new ClassSearch();
+ target.addProvider(provider("", (name, searchPath) -> {
+ visited.add("1");
+ return null;
+ }));
+ target.addProvider(provider("", (name, searchPath) -> {
+ visited.add("2");
+ return null;
+ }));
+
+ try {
+ target.search(searchForList("foo"), null);
+ } catch (InternalError e) {
+ // throws because no provider gives a source
+ }
+
+ Assert.assertEquals(hashset("1", "2"), visited);
+ }
+
+ @Test
+ public void itShouldTryToLoadSaidClassFromClassLoader() {
+ Set<String> loaded = new HashSet<>();
+
+ ClassSearch target = new ClassSearch();
+ target.addProvider(new SourceProvider() {
+ @Override
+ public boolean supports(String type) {
+ return true;
+ }
+
+ @Override
+ public ClassSource findSource(String name, SearchPath searchPath) {
+ return new ClassSource() {
+ @Override
+ public void eachClass(BiConsumer<String, ClassLoader> consumer) {
+ consumer.accept("foo.Bar", new ClassLoader() {
+ @Override
+ public Class<?> loadClass(String nm) throws ClassNotFoundException {
+ loaded.add(nm);
+ return null;
+ }
+ });
+ }
+ };
+ }
+ });
+
+ java.util.List<LoadedClass> search = target.search(searchForList("/tmp/something"), null);
+ Assert.assertEquals(list(new LoadedClass("foo.Bar", null)), search);
+ }
+
+ @Test(expected = InternalError.class)
+ public void itShouldThrowInternalErrorWhenClassLoaderFails() {
+ ClassLoader classLoader = new ClassLoader() {
+ @Override
+ public Class<?> loadClass(String name1) throws ClassNotFoundException {
+ throw new ClassNotFoundException("failed to find " + name1);
+ }
+ };
+
+ ClassSearch target = new ClassSearch();
+ target.addProvider(provider("", (name, searchPath) -> consumer -> consumer.accept("foo.Bar", classLoader)));
+ target.search(searchForList("foobar"), null);
+ }
+
+ private static List<SearchFor> searchForList(String... entries) {
+ List<SearchFor> list = new ArrayList<>();
+ for (String entry : entries) {
+ list.add(new SearchFor(entry));
+ }
+ return list;
+ }
+
+ @SafeVarargs
+ private static <T> List<T> list(T... entries) {
+ List<T> list = new ArrayList<>();
+ for (T entry : entries) {
+ list.add(entry);
+ }
+ return list;
+ }
+
+ @SafeVarargs
+ private static <T> Set<T> hashset(T... entries) {
+ Set<T> set = new HashSet<>();
+ for (T entry : entries) {
+ set.add(entry);
+ }
+ return set;
+ }
+
+ private static class NoopSource implements ClassSource {
+ @Override
+ public void eachClass(BiConsumer<String, ClassLoader> consumer) {
+ }
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java
new file mode 100644
index 000000000..217ef28a2
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @requires vm.aot
+ * @modules jdk.aot/jdk.tools.jaotc
+ * jdk.aot/jdk.tools.jaotc.collect
+ * @build jdk.tools.jaotc.test.collect.Utils
+ * @run junit/othervm jdk.tools.jaotc.test.collect.ClassSourceTest
+ */
+
+
+
+package jdk.tools.jaotc.test.collect;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.nio.file.Paths;
+
+import static jdk.tools.jaotc.collect.ClassSource.makeClassName;
+
+import static jdk.tools.jaotc.test.collect.Utils.getpath;
+
+public class ClassSourceTest {
+ @Test(expected = IllegalArgumentException.class)
+ public void itShouldThrowExceptionIfPathDoesntEndWithClass() {
+ makeClassName(Paths.get("Bar.clazz"));
+ }
+
+ @Test
+ public void itShouldReplaceSlashesWithDots() {
+ Assert.assertEquals("foo.Bar", makeClassName(getpath("foo/Bar.class")));
+ }
+
+ @Test
+ public void itShouldStripLeadingSlash() {
+ Assert.assertEquals("Hello", makeClassName(getpath("/Hello.class")));
+ }
+
+ @Test
+ public void itShouldReplaceMultipleDots() {
+ Assert.assertEquals("some.foo.bar.FooBar", makeClassName(getpath("/some/foo/bar/FooBar.class")));
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java
new file mode 100644
index 000000000..fc7249e3f
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package jdk.tools.jaotc.test.collect;
+
+import java.net.MalformedURLException;
+import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.Set;
+
+import jdk.tools.jaotc.collect.FileSupport;
+
+public class FakeFileSupport extends FileSupport {
+ private final Set<String> exists = new HashSet<>();
+ private final Set<String> directories = new HashSet<>();
+
+ private final Set<String> checkedExists = new HashSet<>();
+ private final Set<String> checkedDirectory = new HashSet<>();
+ private final Set<String> checkedJarFileSystemRoots = new HashSet<>();
+ private final Set<String> classloaderPaths = new HashSet<>();
+
+ private Path jarFileSystemRoot = null;
+ private final ClassLoader classLoader;
+
+ public FakeFileSupport(Set<String> existing, Set<String> directories) {
+ this.exists.addAll(existing);
+ this.directories.addAll(directories);
+
+ classLoader = new ClassLoader() {
+ @Override
+ public Class<?> loadClass(String name) throws ClassNotFoundException {
+ return null;
+ }
+ };
+ }
+
+ public void setJarFileSystemRoot(Path path) {
+ jarFileSystemRoot = path;
+ }
+
+ @Override
+ public boolean exists(Path path) {
+ checkedExists.add(path.toString());
+ return exists.contains(path.toString());
+ }
+
+ @Override
+ public boolean isDirectory(Path path) {
+ checkedDirectory.add(path.toString());
+ return directories.contains(path.toString());
+ }
+
+ @Override
+ public ClassLoader createClassLoader(Path path) throws MalformedURLException {
+ classloaderPaths.add(path.toString());
+ return classLoader;
+ }
+
+ @Override
+ public Path getJarFileSystemRoot(Path jarFile) {
+ checkedJarFileSystemRoots.add(jarFile.toString());
+ return jarFileSystemRoot;
+ }
+
+ @Override
+ public boolean isAbsolute(Path entry) {
+ return entry.toString().startsWith("/");
+ }
+
+ public void addExist(String name) {
+ exists.add(name);
+ }
+
+ public void addDirectory(String name) {
+ directories.add(name);
+ }
+
+ public Set<String> getCheckedExists() {
+ return checkedExists;
+ }
+
+ public Set<String> getCheckedDirectory() {
+ return checkedDirectory;
+ }
+
+ public Set<String> getCheckedJarFileSystemRoots() {
+ return checkedJarFileSystemRoots;
+ }
+
+ public Set<String> getClassloaderPaths() {
+ return classloaderPaths;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java
new file mode 100644
index 000000000..ee286eb44
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package jdk.tools.jaotc.test.collect;
+
+import jdk.tools.jaotc.collect.SearchPath;
+
+import java.nio.file.FileSystem;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Set;
+
+import static jdk.tools.jaotc.test.collect.Utils.set;
+
+public class FakeSearchPath extends SearchPath {
+ private Path path = null;
+ public Set<String> entries = set();
+
+ public FakeSearchPath(String name) {
+ if (name != null) {
+ path = Paths.get(name);
+ }
+ }
+
+ @Override
+ public Path find(FileSystem fileSystem, Path entry, String... defaults) {
+ entries.add(entry.toString());
+ return path;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java
new file mode 100644
index 000000000..3705fc894
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @requires vm.aot
+ * @modules jdk.aot/jdk.tools.jaotc
+ * jdk.aot/jdk.tools.jaotc.collect
+ *
+ * @build jdk.tools.jaotc.test.collect.Utils
+ * @build jdk.tools.jaotc.test.collect.FakeFileSupport
+ * @run junit/othervm jdk.tools.jaotc.test.collect.SearchPathTest
+ */
+
+
+
+package jdk.tools.jaotc.test.collect;
+
+import static jdk.tools.jaotc.test.collect.Utils.mkpath;
+import static jdk.tools.jaotc.test.collect.Utils.mkpaths;
+import static jdk.tools.jaotc.test.collect.Utils.set;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import jdk.tools.jaotc.collect.SearchPath;
+
+public class SearchPathTest {
+ private FakeFileSupport fileSupport;
+ private FileSystem fs;
+
+ @Before
+ public void setUp() throws Exception {
+ fs = FileSystems.getDefault();
+ }
+
+ @Test
+ public void itShouldUsePathIfPathIsAbsoluteAndExisting() {
+ fileSupport = new FakeFileSupport(mkpaths("/foo"), set());
+ SearchPath target = new SearchPath(fileSupport);
+ Path foo = Paths.get(mkpath("/foo"));
+ Path result = target.find(fs, foo);
+ assertSame(result, foo);
+ }
+
+ @Test
+ public void itShouldReturnNullIfPathIsAbsoluteAndNonExisting() {
+ fileSupport = new FakeFileSupport(set(), set());
+ SearchPath target = new SearchPath(fileSupport);
+ Path result = target.find(fs, Paths.get(mkpath("/bar")));
+ assertNull(result);
+ }
+
+ @Test
+ public void itShouldUseRelativeExisting() {
+ fileSupport = new FakeFileSupport(mkpaths("hello", "tmp/hello", "search/hello"), set());
+ SearchPath target = new SearchPath(fileSupport);
+ target.add("search");
+ Path hello = Paths.get("hello");
+ Path result = target.find(fs, hello, "tmp");
+ assertSame(result, hello);
+ }
+
+ @Test
+ public void itShouldSearchDefaultsBeforeSearchPaths() {
+ fileSupport = new FakeFileSupport(mkpaths("bar/foobar"), set());
+ SearchPath target = new SearchPath(fileSupport);
+ Path result = target.find(fs, Paths.get("foobar"), "default1", "bar");
+ assertEquals(mkpath("bar/foobar"), result.toString());
+ assertEquals(mkpaths("foobar", "default1/foobar", "bar/foobar"), fileSupport.getCheckedExists());
+ }
+
+ @Test
+ public void itShouldUseSearchPathsIfNotInDefaults() {
+ fileSupport = new FakeFileSupport(mkpaths("bar/tmp/foobar"), set());
+ SearchPath target = new SearchPath(fileSupport);
+ target.add("foo/tmp", "bar/tmp");
+
+ Path result = target.find(fs, Paths.get("foobar"), "foo", "bar");
+ assertEquals(mkpath("bar/tmp/foobar"), result.toString());
+ assertEquals(mkpaths("foobar", "foo/foobar", "bar/foobar", "bar/tmp/foobar", "foo/tmp/foobar"), fileSupport.getCheckedExists());
+ }
+
+ @Test
+ public void itShouldReturnNullIfNoExistingPathIsFound() {
+ fileSupport = new FakeFileSupport(set(), set());
+ SearchPath target = new SearchPath(fileSupport);
+ target.add("dir1", "dir2");
+
+ Path result = target.find(fs, Paths.get("entry"), "dir3", "dir4");
+ assertNull(result);
+ assertEquals(mkpaths("entry", "dir1/entry", "dir2/entry", "dir3/entry", "dir4/entry"), fileSupport.getCheckedExists());
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/Utils.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/Utils.java
new file mode 100644
index 000000000..cd1931ce9
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/Utils.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package jdk.tools.jaotc.test.collect;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashSet;
+import java.util.Set;
+
+public class Utils {
+ @SafeVarargs
+ public static <T> Set<T> set(T... entries) {
+ Set<T> set = new HashSet<>();
+ for (T entry : entries) {
+ set.add(entry);
+ }
+ return set;
+ }
+
+ public static String mkpath(String path) {
+ return getpath(path).toString();
+ }
+
+ public static Set<String> mkpaths(String... paths) {
+ Set<String> set = new HashSet<>();
+ for (String entry : paths) {
+ set.add(mkpath(entry));
+ }
+ return set;
+ }
+
+ public static Path getpath(String path) {
+ if (path.startsWith("/") && System.getProperty("os.name").startsWith("Windows")) {
+ return Paths.get(new File(path).getAbsolutePath());
+ } else {
+ return Paths.get(path);
+ }
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java
new file mode 100644
index 000000000..30ee14481
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @requires vm.aot
+ * @modules jdk.aot/jdk.tools.jaotc
+ * jdk.aot/jdk.tools.jaotc.collect
+ * jdk.aot/jdk.tools.jaotc.collect.directory
+ * @compile ../Utils.java
+ * @compile ../FakeFileSupport.java
+ * @run junit/othervm jdk.tools.jaotc.test.collect.directory.DirectorySourceProviderTest
+ */
+
+
+
+package jdk.tools.jaotc.test.collect.directory;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.directory.DirectorySourceProvider;
+import jdk.tools.jaotc.test.collect.FakeFileSupport;
+import jdk.tools.jaotc.collect.FileSupport;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.net.MalformedURLException;
+import java.nio.file.Path;
+import java.util.Set;
+
+import static jdk.tools.jaotc.test.collect.Utils.set;
+
+public class DirectorySourceProviderTest {
+ @Test
+ public void itShouldReturnNullForNonExistantPath() {
+ DirectorySourceProvider target = new DirectorySourceProvider(new FakeFileSupport(set(), set()));
+ ClassSource result = target.findSource("hello", null);
+ Assert.assertNull(result);
+ }
+
+ @Test
+ public void itShouldReturnNullForNonDirectory() {
+ DirectorySourceProvider target = new DirectorySourceProvider(new FakeFileSupport(set("foobar"), set()));
+ ClassSource result = target.findSource("foobar", null);
+ Assert.assertNull(result);
+ }
+
+ @Test
+ public void itShouldReturnNullForMalformedURI() {
+ Set<String> visited = set();
+ DirectorySourceProvider target = new DirectorySourceProvider(new FakeFileSupport(set("foobar"), set("foobar")) {
+ @Override
+ public ClassLoader createClassLoader(Path path) throws MalformedURLException {
+ visited.add("1");
+ throw new MalformedURLException("...");
+ }
+ });
+ ClassSource result = target.findSource("foobar", null);
+ Assert.assertNull(result);
+ Assert.assertEquals(set("1"), visited);
+ }
+
+ @Test
+ public void itShouldCreateSourceIfNameExistsAndIsADirectory() {
+ FileSupport fileSupport = new FakeFileSupport(set("foo"), set("foo"));
+ DirectorySourceProvider target = new DirectorySourceProvider(fileSupport);
+ ClassSource foo = target.findSource("foo", null);
+ Assert.assertNotNull(foo);
+ Assert.assertEquals("directory:foo", foo.toString());
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java
new file mode 100644
index 000000000..86624c10d
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @requires vm.aot
+ * @modules jdk.aot/jdk.tools.jaotc
+ * jdk.aot/jdk.tools.jaotc.collect
+ * jdk.aot/jdk.tools.jaotc.collect.jar
+ * @compile ../Utils.java
+ * @compile ../FakeFileSupport.java
+ * @compile ../FakeSearchPath.java
+ *
+ * @run junit/othervm jdk.tools.jaotc.test.collect.jar.JarSourceProviderTest
+ */
+
+
+
+package jdk.tools.jaotc.test.collect.jar;
+
+import static jdk.tools.jaotc.test.collect.Utils.mkpath;
+import static jdk.tools.jaotc.test.collect.Utils.set;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.ProviderNotFoundException;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.jar.JarSourceProvider;
+import jdk.tools.jaotc.test.collect.FakeFileSupport;
+import jdk.tools.jaotc.test.collect.FakeSearchPath;
+
+public class JarSourceProviderTest {
+
+ private FakeFileSupport fileSupport;
+ private JarSourceProvider target;
+
+ @Before
+ public void setUp() throws Exception {
+ fileSupport = new FakeFileSupport(set(), set());
+ target = new JarSourceProvider(fileSupport);
+ }
+
+ @Test
+ public void itShouldUseSearchPathToFindPath() {
+ FakeSearchPath searchPath = new FakeSearchPath(null);
+ target.findSource("hello", searchPath);
+
+ Assert.assertEquals(set("hello"), searchPath.entries);
+ }
+
+ @Test
+ public void itShouldReturnNullIfPathIsNull() {
+ ClassSource source = target.findSource("foobar", new FakeSearchPath(null));
+ Assert.assertNull(source);
+ }
+
+ @Test
+ public void itShouldReturnNullIfPathIsDirectory() {
+ fileSupport.addDirectory("hello/foobar");
+ ClassSource source = target.findSource("foobar", new FakeSearchPath("hello/foobar"));
+
+ Assert.assertNull(source);
+ Assert.assertEquals(set(mkpath("hello/foobar")), fileSupport.getCheckedDirectory());
+ }
+
+ @Test
+ public void itShouldReturnNullIfUnableToMakeJarFileSystem() {
+ fileSupport.setJarFileSystemRoot(null);
+ ClassSource result = target.findSource("foobar", new FakeSearchPath("foo/bar"));
+
+ Assert.assertEquals(set(mkpath("foo/bar")), fileSupport.getCheckedJarFileSystemRoots());
+ Assert.assertNull(result);
+ }
+
+ @Test
+ public void itShouldReturnNullIfNotValidJarProvider() {
+ fileSupport = new FakeFileSupport(set(), set()) {
+
+ @Override
+ public Path getJarFileSystemRoot(Path jarFile) {
+ super.getJarFileSystemRoot(jarFile);
+ throw new ProviderNotFoundException();
+ }
+ };
+ fileSupport.setJarFileSystemRoot(null);
+ target = new JarSourceProvider(fileSupport);
+
+ ClassSource result = target.findSource("foobar", new FakeSearchPath("foo/bar"));
+
+ Assert.assertEquals(set(mkpath("foo/bar")), fileSupport.getCheckedJarFileSystemRoots());
+ Assert.assertNull(result);
+ }
+
+ @Test
+ public void itShouldReturnSourceWhenAllIsValid() {
+ fileSupport.setJarFileSystemRoot(Paths.get("some/bar"));
+ ClassSource result = target.findSource("foobar", new FakeSearchPath("this/bar"));
+
+ Assert.assertEquals(set(mkpath("this/bar")), fileSupport.getClassloaderPaths());
+ Assert.assertEquals("jar:" + mkpath("this/bar"), result.toString());
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java
new file mode 100644
index 000000000..9fab0af81
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @requires vm.aot
+ * @modules jdk.aot/jdk.tools.jaotc
+ * jdk.aot/jdk.tools.jaotc.collect
+ * jdk.aot/jdk.tools.jaotc.collect.module
+ * @compile ../Utils.java
+ * @run junit/othervm jdk.tools.jaotc.test.collect.module.ModuleSourceProviderTest
+ */
+
+
+
+package jdk.tools.jaotc.test.collect.module;
+
+import static jdk.tools.jaotc.test.collect.Utils.mkpath;
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.function.BiFunction;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.module.ModuleSource;
+import jdk.tools.jaotc.collect.module.ModuleSourceProvider;
+
+public class ModuleSourceProviderTest {
+ private ClassLoader classLoader;
+ private ModuleSourceProvider target;
+ private FileSupport fileSupport;
+ private BiFunction<Path, Path, Path> getSubDirectory = null;
+
+ @Before
+ public void setUp() {
+ classLoader = new FakeClassLoader();
+ fileSupport = new FileSupport() {
+
+ @Override
+ public boolean isDirectory(Path path) {
+ return true;
+ }
+
+ @Override
+ public Path getSubDirectory(FileSystem fileSystem, Path root, Path path) throws IOException {
+ if (getSubDirectory == null) {
+ throw new IOException("Nope");
+ }
+ return getSubDirectory.apply(root, path);
+ }
+ };
+ target = new ModuleSourceProvider(FileSystems.getDefault(), classLoader, fileSupport);
+ }
+
+ @Test
+ public void itShouldUseFileSupport() {
+ getSubDirectory = (root, path) -> {
+ if (root.toString().equals("modules") && path.toString().equals("test.module")) {
+ return Paths.get("modules/test.module");
+ }
+ return null;
+ };
+
+ ModuleSource source = (ModuleSource) target.findSource("test.module", null);
+ assertEquals(mkpath("modules/test.module"), source.getModulePath().toString());
+ assertEquals("module:" + mkpath("modules/test.module"), source.toString());
+ }
+
+ private static class FakeClassLoader extends ClassLoader {
+ @Override
+ public Class<?> loadClass(String name) throws ClassNotFoundException {
+ return null;
+ }
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java
new file mode 100644
index 000000000..45ad9a594
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import java.util.ListIterator;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.GraalCompiler;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
+import org.graalvm.compiler.hotspot.meta.HotSpotInvokeDynamicPlugin;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.Suites;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.DefaultProfilingInfo;
+import jdk.vm.ci.meta.ProfilingInfo;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.TriState;
+
+final class AOTBackend {
+ private final Main main;
+ private final OptionValues graalOptions;
+ private final HotSpotBackend backend;
+ private final HotSpotProviders providers;
+ private final HotSpotCodeCacheProvider codeCache;
+ private final PhaseSuite<HighTierContext> graphBuilderSuite;
+ private final HighTierContext highTierContext;
+
+ AOTBackend(Main main, OptionValues graalOptions, HotSpotBackend backend, HotSpotInvokeDynamicPlugin inokeDynamicPlugin) {
+ this.main = main;
+ this.graalOptions = graalOptions;
+ this.backend = backend;
+ providers = backend.getProviders();
+ codeCache = providers.getCodeCache();
+ graphBuilderSuite = initGraphBuilderSuite(backend, main.options.compileWithAssertions, inokeDynamicPlugin);
+ highTierContext = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.ALL);
+ }
+
+ PhaseSuite<HighTierContext> getGraphBuilderSuite() {
+ return graphBuilderSuite;
+ }
+
+ HotSpotBackend getBackend() {
+ return backend;
+ }
+
+ HotSpotProviders getProviders() {
+ return providers;
+ }
+
+ private Suites getSuites() {
+ // create suites every time, as we modify options for the compiler
+ return backend.getSuites().getDefaultSuites(graalOptions);
+ }
+
+ private LIRSuites getLirSuites() {
+ // create suites every time, as we modify options for the compiler
+ return backend.getSuites().getDefaultLIRSuites(graalOptions);
+ }
+
+ @SuppressWarnings("try")
+ CompilationResult compileMethod(ResolvedJavaMethod resolvedMethod, DebugContext debug) {
+ StructuredGraph graph = buildStructuredGraph(resolvedMethod, debug);
+ if (graph != null) {
+ return compileGraph(resolvedMethod, graph, debug);
+ }
+ return null;
+ }
+
+ /**
+ * Build a structured graph for the member.
+ *
+ * @param javaMethod method for whose code the graph is to be created
+ * @param debug
+ * @return structured graph
+ */
+ @SuppressWarnings("try")
+ private StructuredGraph buildStructuredGraph(ResolvedJavaMethod javaMethod, DebugContext debug) {
+ try (DebugContext.Scope s = debug.scope("AOTParseMethod")) {
+ StructuredGraph graph = new StructuredGraph.Builder(graalOptions, debug).method(javaMethod).useProfilingInfo(false).build();
+ graphBuilderSuite.apply(graph, highTierContext);
+ return graph;
+ } catch (Throwable e) {
+ main.handleError(javaMethod, e, " (building graph)");
+ }
+ return null;
+ }
+
+ @SuppressWarnings("try")
+ private CompilationResult compileGraph(ResolvedJavaMethod resolvedMethod, StructuredGraph graph, DebugContext debug) {
+ try (DebugContext.Scope s = debug.scope("AOTCompileMethod")) {
+ ProfilingInfo profilingInfo = DefaultProfilingInfo.get(TriState.FALSE);
+
+ final boolean isImmutablePIC = true;
+ CompilationIdentifier id = new CompilationIdentifier() {
+ @Override
+ public String toString(Verbosity verbosity) {
+ return resolvedMethod.getName();
+ }
+ };
+ CompilationResult compilationResult = new CompilationResult(id, isImmutablePIC);
+
+ return GraalCompiler.compileGraph(graph, resolvedMethod, providers, backend, graphBuilderSuite, OptimisticOptimizations.ALL, profilingInfo, getSuites(), getLirSuites(),
+ compilationResult, CompilationResultBuilderFactory.Default, true);
+
+ } catch (Throwable e) {
+ main.handleError(resolvedMethod, e, " (compiling graph)");
+ }
+ return null;
+ }
+
+ private static PhaseSuite<HighTierContext> initGraphBuilderSuite(HotSpotBackend backend, boolean compileWithAssertions, HotSpotInvokeDynamicPlugin inokeDynamicPlugin) {
+ PhaseSuite<HighTierContext> graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
+ ListIterator<BasePhase<? super HighTierContext>> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class);
+ GraphBuilderConfiguration baseConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig();
+
+ // Use all default plugins.
+ Plugins plugins = baseConfig.getPlugins();
+ plugins.setInvokeDynamicPlugin(inokeDynamicPlugin);
+ GraphBuilderConfiguration aotConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withOmitAssertions(!compileWithAssertions);
+
+ iterator.next();
+ iterator.remove();
+ iterator.add(new GraphBuilderPhase(aotConfig));
+
+ return graphBuilderSuite;
+ }
+
+ void printCompiledMethod(HotSpotResolvedJavaMethod resolvedMethod, CompilationResult compResult) {
+ // This is really not installing the method.
+ InstalledCode installedCode = codeCache.addCode(resolvedMethod, HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, resolvedMethod, null, compResult, graalOptions), null, null);
+ String disassembly = codeCache.disassemble(installedCode);
+ if (disassembly != null) {
+ main.printer.printlnDebug(disassembly);
+ }
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java
new file mode 100644
index 000000000..b3a72f981
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.GraalCompilerOptions;
+import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.debug.DebugContext.Activation;
+import org.graalvm.compiler.debug.DebugContext.Builder;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
+import org.graalvm.compiler.serviceprovider.GraalServices;
+
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.runtime.JVMCICompiler;
+
+/**
+ * Represents a task in the compile queue.
+ *
+ * This class encapsulates all Graal-specific information that is used during offline AOT
+ * compilation of classes. It also defines methods that parse compilation result of Graal to create
+ * target-independent representation {@code BinaryContainer} of the intended target binary.
+ */
+final class AOTCompilationTask implements Runnable, Comparable<Object> {
+
+ private static final AtomicInteger ids = new AtomicInteger();
+
+ private final Main main;
+
+ private OptionValues graalOptions;
+
+ /**
+ * The compilation id of this task.
+ */
+ private final int id;
+
+ private final AOTCompiledClass holder;
+
+ /**
+ * Method this task represents.
+ */
+ private final ResolvedJavaMethod method;
+
+ private final AOTBackend aotBackend;
+
+ /**
+ * The result of this compilation task.
+ */
+ private CompiledMethodInfo result;
+
+ AOTCompilationTask(Main main, OptionValues graalOptions, AOTCompiledClass holder, ResolvedJavaMethod method, AOTBackend aotBackend) {
+ this.main = main;
+ this.graalOptions = graalOptions;
+ this.id = ids.incrementAndGet();
+ this.holder = holder;
+ this.method = method;
+ this.aotBackend = aotBackend;
+ }
+
+ /**
+ * Compile a method or a constructor.
+ */
+ @Override
+ @SuppressWarnings("try")
+ public void run() {
+ // Ensure a JVMCI runtime is initialized prior to Debug being initialized as the former
+ // may include processing command line options used by the latter.
+ HotSpotJVMCIRuntime.runtime();
+
+ AOTCompiler.logCompilation(JavaMethodInfo.uniqueMethodName(method), "Compiling");
+
+ final long threadId = Thread.currentThread().getId();
+
+ final boolean printCompilation = GraalCompilerOptions.PrintCompilation.getValue(graalOptions) && !TTY.isSuppressed() && GraalServices.isThreadAllocatedMemorySupported();
+ if (printCompilation) {
+ TTY.println(getMethodDescription() + "...");
+ }
+
+ final long start;
+ final long allocatedBytesBefore;
+ if (printCompilation) {
+ start = System.currentTimeMillis();
+ allocatedBytesBefore = GraalServices.getThreadAllocatedBytes(threadId);
+ } else {
+ start = 0L;
+ allocatedBytesBefore = 0L;
+ }
+
+ CompilationResult compResult = null;
+ final long startTime = System.currentTimeMillis();
+ SnippetReflectionProvider snippetReflection = aotBackend.getProviders().getSnippetReflection();
+ try (DebugContext debug = new Builder(graalOptions, new GraalDebugHandlersFactory(snippetReflection)).build(); Activation a = debug.activate()) {
+ compResult = aotBackend.compileMethod(method, debug);
+ }
+ final long endTime = System.currentTimeMillis();
+
+ if (printCompilation) {
+ final long stop = System.currentTimeMillis();
+ final int targetCodeSize = compResult != null ? compResult.getTargetCodeSize() : -1;
+ final long allocatedBytesAfter = GraalServices.getThreadAllocatedBytes(threadId);
+ final long allocatedBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024;
+
+ TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dkB", stop - start, targetCodeSize, allocatedBytes));
+ }
+
+ if (compResult == null) {
+ result = null;
+ return;
+ }
+
+ // For now precision to the nearest second is sufficient.
+ LogPrinter.writeLog(" Compile Time: " + TimeUnit.MILLISECONDS.toSeconds(endTime - startTime) + "secs");
+ if (main.options.debug) {
+ aotBackend.printCompiledMethod((HotSpotResolvedJavaMethod) method, compResult);
+ }
+
+ result = new CompiledMethodInfo(compResult, new AOTHotSpotResolvedJavaMethod((HotSpotResolvedJavaMethod) method, aotBackend.getBackend(), graalOptions));
+ }
+
+ private String getMethodDescription() {
+ return String.format("%-6d aot %s %s", getId(), JavaMethodInfo.uniqueMethodName(method),
+ getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + getEntryBCI() + ") ");
+ }
+
+ private int getId() {
+ return id;
+ }
+
+ private static int getEntryBCI() {
+ return JVMCICompiler.INVOCATION_ENTRY_BCI;
+ }
+
+ ResolvedJavaMethod getMethod() {
+ return method;
+ }
+
+ /**
+ * Returns the holder of this method as a {@link AOTCompiledClass}.
+ *
+ * @return the holder of this method
+ */
+ AOTCompiledClass getHolder() {
+ return holder;
+ }
+
+ /**
+ * Returns the result of this compilation task.
+ *
+ * @return result of this compilation task
+ */
+ CompiledMethodInfo getResult() {
+ return result;
+ }
+
+ @Override
+ public int compareTo(Object obj) {
+ AOTCompilationTask other = (AOTCompilationTask) obj;
+ return this.id - other.id;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ AOTCompilationTask other = (AOTCompilationTask) obj;
+ return (this.id == other.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 + id;
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java
new file mode 100644
index 000000000..416d332fc
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java
@@ -0,0 +1,471 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Set;
+
+import jdk.tools.jaotc.AOTDynamicTypeStore.AdapterLocation;
+import jdk.tools.jaotc.AOTDynamicTypeStore.AppendixLocation;
+import jdk.tools.jaotc.AOTDynamicTypeStore.Location;
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Class encapsulating Graal-compiled output of a Java class. The compilation result of all methods
+ * of a class {@code className} are maintained in an array list.
+ */
+final class AOTCompiledClass {
+
+ private static AOTDynamicTypeStore dynoStore;
+
+ static void setDynamicTypeStore(AOTDynamicTypeStore s) {
+ dynoStore = s;
+ }
+
+ static class AOTKlassData {
+ private int gotIndex; // Index (offset/8) to the got in the .metaspace.got section
+ private int classId; // Unique ID
+ // Offset to compiled methods data in the .methods.offsets section.
+ private int compiledMethodsOffset;
+ // Offset to dependent methods data.
+ private int dependentMethodsOffset;
+
+ private final String metadataName;
+ HotSpotResolvedObjectType type;
+
+ /**
+ * List of dependent compiled methods which have a reference to this class.
+ */
+ private ArrayList<CompiledMethodInfo> dependentMethods;
+
+ AOTKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type, int classId) {
+ this.dependentMethods = new ArrayList<>();
+ this.classId = classId;
+ this.type = type;
+ this.metadataName = type.getName();
+ this.gotIndex = binaryContainer.addTwoSlotKlassSymbol(metadataName);
+ this.compiledMethodsOffset = -1; // Not compiled classes do not have compiled methods.
+ this.dependentMethodsOffset = -1;
+ }
+
+ private String[] getMetaspaceNames() {
+ String name = metadataName;
+ Set<Location> locs = dynoStore.getDynamicClassLocationsForType(type);
+ if (locs == null) {
+ return new String[]{name};
+ } else {
+ ArrayList<String> names = new ArrayList<>();
+ names.add(name);
+ for (Location l : locs) {
+ HotSpotResolvedObjectType cpType = l.getHolder();
+ AOTKlassData data = getAOTKlassData(cpType);
+ // We collect dynamic types at parse time, but late inlining
+ // may record types that don't make it into the final graph.
+ // We can safely ignore those here.
+ if (data == null) {
+ // Not a compiled or inlined method
+ continue;
+ }
+ int cpi = l.getCpi();
+ String location = "<" + data.classId + ":" + cpi + ">";
+ if (l instanceof AdapterLocation) {
+ names.add("adapter" + location);
+ AdapterLocation a = (AdapterLocation) l;
+ names.add("adapter:" + a.getMethodId() + location);
+ } else {
+ assert l instanceof AppendixLocation;
+ names.add("appendix" + location);
+ }
+ }
+ return names.toArray(new String[names.size()]);
+ }
+ }
+
+ HotSpotResolvedObjectType getType() {
+ return type;
+ }
+
+ String getMetadataName() {
+ return metadataName;
+ }
+
+ /**
+ * Add a method to the list of dependent methods.
+ */
+ synchronized boolean addDependentMethod(CompiledMethodInfo cm) {
+ return dependentMethods.add(cm);
+ }
+
+ /**
+ * Return the array list of dependent class methods.
+ *
+ * @return array list of dependent methods
+ */
+ ArrayList<CompiledMethodInfo> getDependentMethods() {
+ return dependentMethods;
+ }
+
+ /**
+ * Returns if this class has dependent methods.
+ *
+ * @return true if dependent methods exist, false otherwise
+ */
+ boolean hasDependentMethods() {
+ return !dependentMethods.isEmpty();
+ }
+
+ void setCompiledMethodsOffset(int offset) {
+ compiledMethodsOffset = offset;
+ }
+
+ protected void putAOTKlassData(BinaryContainer binaryContainer, ReadOnlyDataContainer container) {
+ int cntDepMethods = dependentMethods.size();
+ // Create array of dependent methods IDs. First word is count.
+ ReadOnlyDataContainer dependenciesContainer = binaryContainer.getKlassesDependenciesContainer();
+ this.dependentMethodsOffset = BinaryContainer.addMethodsCount(cntDepMethods, dependenciesContainer);
+ for (CompiledMethodInfo methodInfo : dependentMethods) {
+ dependenciesContainer.appendInt(methodInfo.getCodeId());
+ }
+
+ verify();
+
+ // @formatter:off
+ /*
+ * The offsets layout should match AOTKlassData structure in AOT JVM runtime
+ */
+ int offset = container.getByteStreamSize();
+ for (String name : getMetaspaceNames()) {
+ container.createSymbol(offset, Kind.OBJECT, Binding.GLOBAL, 0, name);
+ }
+ // Add index (offset/8) to the got in the .metaspace.got section
+ container.appendInt(gotIndex).
+ // Add unique ID
+ appendInt(classId).
+ // Add the offset to compiled methods data in the .metaspace.offsets section.
+ appendInt(compiledMethodsOffset).
+ // Add the offset to dependent methods data in the .metaspace.offsets section.
+ appendInt(dependentMethodsOffset).
+ // Add fingerprint.
+ appendLong(type.getFingerprint());
+
+ // @formatter:on
+ }
+
+ private void verify() {
+ String name = type.getName();
+ assert gotIndex > 0 : "incorrect gotIndex: " + gotIndex + " for klass: " + name;
+ long fingerprint = type.getFingerprint();
+ assert type.isArray() || fingerprint != 0 : "incorrect fingerprint: " + fingerprint + " for klass: " + name;
+ assert compiledMethodsOffset >= -1 : "incorrect compiledMethodsOffset: " + compiledMethodsOffset + " for klass: " + name;
+ assert dependentMethodsOffset >= -1 : "incorrect dependentMethodsOffset: " + dependentMethodsOffset + " for klass: " + name;
+ assert classId >= 0 : "incorrect classId: " + classId + " for klass: " + name;
+ }
+
+ }
+
+ private final HotSpotResolvedObjectType resolvedJavaType;
+
+ /**
+ * List of all collected class data.
+ */
+ private static HashMap<String, AOTKlassData> klassData = new HashMap<>();
+
+ /**
+ * List of all methods to be compiled.
+ */
+ private ArrayList<ResolvedJavaMethod> methods = new ArrayList<>();
+
+ /**
+ * List of all compiled class methods.
+ */
+ private ArrayList<CompiledMethodInfo> compiledMethods;
+
+ /**
+ * If this class represents Graal stub code.
+ */
+ private final boolean representsStubs;
+
+ /**
+ * Classes count used to generate unique global method id.
+ */
+ private static int classesCount = 0;
+
+ /**
+ * Construct an object with compiled methods. Intended to be used for code with no corresponding
+ * Java method name in the user application.
+ *
+ * @param compiledMethods AOT compiled methods
+ */
+ AOTCompiledClass(ArrayList<CompiledMethodInfo> compiledMethods) {
+ this.resolvedJavaType = null;
+ this.compiledMethods = compiledMethods;
+ this.representsStubs = true;
+ }
+
+ /**
+ * Construct an object with compiled versions of the named class.
+ */
+ AOTCompiledClass(ResolvedJavaType resolvedJavaType) {
+ this.resolvedJavaType = (HotSpotResolvedObjectType) resolvedJavaType;
+ this.compiledMethods = new ArrayList<>();
+ this.representsStubs = false;
+ }
+
+ /**
+ * @return the ResolvedJavaType of this class
+ */
+ ResolvedJavaType getResolvedJavaType() {
+ return resolvedJavaType;
+ }
+
+ /**
+ * Get the list of methods which should be compiled.
+ */
+ ArrayList<ResolvedJavaMethod> getMethods() {
+ ArrayList<ResolvedJavaMethod> m = methods;
+ methods = null; // Free - it is not used after that.
+ return m;
+ }
+
+ /**
+ * Get the number of all AOT classes.
+ */
+ static int getClassesCount() {
+ return classesCount;
+ }
+
+ /**
+ * Get the number of methods which should be compiled.
+ *
+ * @return number of methods which should be compiled
+ */
+ int getMethodCount() {
+ return methods.size();
+ }
+
+ /**
+ * Add a method to the list of methods to be compiled.
+ */
+ void addMethod(ResolvedJavaMethod method) {
+ methods.add(method);
+ }
+
+ /**
+ * Returns if this class has methods which should be compiled.
+ *
+ * @return true if this class contains methods which should be compiled, false otherwise
+ */
+ boolean hasMethods() {
+ return !methods.isEmpty();
+ }
+
+ /**
+ * Add a method to the list of compiled methods. This method needs to be thread-safe.
+ */
+ synchronized boolean addCompiledMethod(CompiledMethodInfo cm) {
+ return compiledMethods.add(cm);
+ }
+
+ /**
+ * Return the array list of compiled class methods.
+ *
+ * @return array list of compiled methods
+ */
+ ArrayList<CompiledMethodInfo> getCompiledMethods() {
+ return compiledMethods;
+ }
+
+ /**
+ * Returns if this class has successfully compiled methods.
+ *
+ * @return true if methods were compiled, false otherwise
+ */
+ boolean hasCompiledMethods() {
+ return !compiledMethods.isEmpty();
+ }
+
+ /**
+ * Add a klass data.
+ */
+ static synchronized AOTKlassData addAOTKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) {
+ AOTKlassData data = getAOTKlassData(type);
+ if (data == null) {
+ data = new AOTKlassData(binaryContainer, type, classesCount++);
+ klassData.put(type.getName(), data);
+ }
+ return data;
+ }
+
+ static synchronized AOTKlassData getAOTKlassData(HotSpotResolvedObjectType type) {
+ String name = type.getName();
+ AOTKlassData data = klassData.get(name);
+ if (data != null) {
+ HotSpotResolvedObjectType oldType = data.getType();
+ assert oldType.equals(type) : "duplicate classes for name " + type.getName();
+ }
+ return data;
+ }
+
+ void addAOTKlassData(BinaryContainer binaryContainer) {
+ for (CompiledMethodInfo methodInfo : compiledMethods) {
+ // Record methods holder
+ methodInfo.addDependentKlassData(binaryContainer, resolvedJavaType);
+ // Record inlinee classes
+ ResolvedJavaMethod[] inlinees = methodInfo.getCompilationResult().getMethods();
+ if (inlinees != null) {
+ for (ResolvedJavaMethod m : inlinees) {
+ methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass());
+ }
+ }
+ // Record classes of fields that were accessed
+ ResolvedJavaField[] fields = methodInfo.getCompilationResult().getFields();
+ if (fields != null) {
+ for (ResolvedJavaField f : fields) {
+ methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass());
+ }
+ }
+ }
+ }
+
+ static synchronized AOTKlassData addFingerprintKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) {
+ if (type.isArray()) {
+ return addAOTKlassData(binaryContainer, type);
+ }
+ assert type.getFingerprint() != 0 : "no fingerprint for " + type.getName();
+ AOTKlassData old = getAOTKlassData(type);
+ if (old != null) {
+ if (areAssertionsEnabled()) {
+ HotSpotResolvedObjectType s = type.getSuperclass();
+ if (s != null) {
+ assert getAOTKlassData(s) != null : "fingerprint for super " + s.getName() + " needed for " + type.getName();
+ }
+ for (HotSpotResolvedObjectType i : type.getInterfaces()) {
+ assert getAOTKlassData(i) != null : "fingerprint for interface " + i.getName() + " needed for " + type.getName();
+ }
+ }
+ return old;
+ }
+
+ // Fingerprinting requires super classes and super interfaces
+ HotSpotResolvedObjectType s = type.getSuperclass();
+ if (s != null) {
+ addFingerprintKlassData(binaryContainer, s);
+ }
+ for (HotSpotResolvedObjectType i : type.getInterfaces()) {
+ addFingerprintKlassData(binaryContainer, i);
+ }
+
+ return addAOTKlassData(binaryContainer, type);
+ }
+
+ @SuppressWarnings("all")
+ private static boolean areAssertionsEnabled() {
+ boolean assertsEnabled = false;
+ // Next assignment will be executed when asserts are enabled.
+ assert assertsEnabled = true;
+ return assertsEnabled;
+ }
+
+ /*
+ * Put methods data to contained.
+ */
+ void putMethodsData(BinaryContainer binaryContainer) {
+ ReadOnlyDataContainer container = binaryContainer.getMethodsOffsetsContainer();
+ int cntMethods = compiledMethods.size();
+ int startMethods = BinaryContainer.addMethodsCount(cntMethods, container);
+ for (CompiledMethodInfo methodInfo : compiledMethods) {
+ methodInfo.addMethodOffsets(binaryContainer, container);
+ }
+ String name = resolvedJavaType.getName();
+ AOTKlassData data = getAOTKlassData(resolvedJavaType);
+ assert data != null : "missing data for klass: " + name;
+ int cntDepMethods = data.dependentMethods.size();
+ assert cntDepMethods > 0 : "no dependent methods for compiled klass: " + name;
+ data.setCompiledMethodsOffset(startMethods);
+ }
+
+ static void putAOTKlassData(BinaryContainer binaryContainer) {
+ // record dynamic types
+ Set<HotSpotResolvedObjectType> dynoTypes = dynoStore.getDynamicTypes();
+ if (dynoTypes != null) {
+ for (HotSpotResolvedObjectType dynoType : dynoTypes) {
+ addFingerprintKlassData(binaryContainer, dynoType);
+ }
+ }
+
+ ReadOnlyDataContainer container = binaryContainer.getKlassesOffsetsContainer();
+ for (AOTKlassData data : klassData.values()) {
+ data.putAOTKlassData(binaryContainer, container);
+ }
+ }
+
+ static HotSpotResolvedObjectType getType(Object ref) {
+ return (ref instanceof HotSpotResolvedObjectType) ? (HotSpotResolvedObjectType) ref : ((HotSpotResolvedJavaMethod) ref).getDeclaringClass();
+ }
+
+ static String metadataName(HotSpotResolvedObjectType type) {
+ AOTKlassData data = getAOTKlassData(type);
+ assert data != null : "no data for " + type;
+ return getAOTKlassData(type).getMetadataName();
+ }
+
+ private static String metadataName(HotSpotResolvedJavaMethod m) {
+ return metadataName(m.getDeclaringClass()) + "." + m.getName() + m.getSignature().toMethodDescriptor();
+ }
+
+ static String metadataName(Object ref) {
+ if (ref instanceof HotSpotResolvedJavaMethod) {
+ HotSpotResolvedJavaMethod m = (HotSpotResolvedJavaMethod) ref;
+ return metadataName(m);
+ } else {
+ assert ref instanceof HotSpotResolvedObjectType : "unexpected object type " + ref.getClass().getName();
+ HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) ref;
+ return metadataName(type);
+ }
+ }
+
+ boolean representsStubs() {
+ return representsStubs;
+ }
+
+ void clear() {
+ for (CompiledMethodInfo c : compiledMethods) {
+ c.clear();
+ }
+ this.compiledMethods = null;
+ this.methods = null;
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiler.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiler.java
new file mode 100644
index 000000000..4bf9047a4
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiler.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.graalvm.compiler.options.OptionValues;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+final class AOTCompiler {
+
+ private final Main main;
+
+ private final OptionValues graalOptions;
+
+ private CompileQueue compileQueue;
+
+ private final AOTBackend backend;
+
+ /**
+ * Compile queue.
+ */
+ private class CompileQueue extends ThreadPoolExecutor {
+
+ /**
+ * Time of the start of this queue.
+ */
+ private final long startTime;
+
+ /**
+ * Method counter for successful compilations.
+ */
+ private final AtomicInteger successfulMethodCount = new AtomicInteger();
+
+ /**
+ * Method counter for failed compilations.
+ */
+ private final AtomicInteger failedMethodCount = new AtomicInteger();
+
+ /**
+ * Create a compile queue with the given number of threads.
+ */
+ CompileQueue(final int threads) {
+ super(threads, threads, 0L, TimeUnit.MILLISECONDS, new PriorityBlockingQueue<>());
+ startTime = System.currentTimeMillis();
+ }
+
+ @Override
+ protected void afterExecute(Runnable r, Throwable t) {
+ AOTCompilationTask task = (AOTCompilationTask) r;
+ if (task.getResult() != null) {
+ final int count = successfulMethodCount.incrementAndGet();
+ if (count % 100 == 0) {
+ main.printer.printInfo(".");
+ }
+ CompiledMethodInfo result = task.getResult();
+ if (result != null) {
+ task.getHolder().addCompiledMethod(result);
+ }
+ } else {
+ failedMethodCount.incrementAndGet();
+ main.printer.printlnVerbose("");
+ ResolvedJavaMethod method = task.getMethod();
+ main.printer.printlnVerbose(" failed " + method.getName() + method.getSignature().toMethodDescriptor());
+ }
+ }
+
+ @Override
+ protected void terminated() {
+ final long endTime = System.currentTimeMillis();
+ final int success = successfulMethodCount.get();
+ final int failed = failedMethodCount.get();
+ main.printer.printlnInfo("");
+ main.printer.printlnInfo(success + " methods compiled, " + failed + " methods failed (" + (endTime - startTime) + " ms)");
+ }
+
+ }
+
+ /**
+ * @param main
+ * @param graalOptions
+ * @param aotBackend
+ * @param threads number of compilation threads
+ */
+ AOTCompiler(Main main, OptionValues graalOptions, AOTBackend aotBackend, final int threads) {
+ this.main = main;
+ this.graalOptions = graalOptions;
+ this.compileQueue = new CompileQueue(threads);
+ this.backend = aotBackend;
+ }
+
+ /**
+ * Compile all methods in all classes passed.
+ *
+ * @param classes a list of class to compile
+ * @throws InterruptedException
+ */
+ List<AOTCompiledClass> compileClasses(List<AOTCompiledClass> classes) throws InterruptedException {
+ main.printer.printlnInfo("Compiling with " + compileQueue.getCorePoolSize() + " threads");
+ main.printer.printInfo("."); // Compilation progress indication.
+
+ for (AOTCompiledClass c : classes) {
+ for (ResolvedJavaMethod m : c.getMethods()) {
+ enqueueMethod(c, m);
+ }
+ }
+
+ // Shutdown queue and wait for all tasks to complete.
+ compileQueue.shutdown();
+ compileQueue.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
+
+ List<AOTCompiledClass> compiledClasses = new ArrayList<>();
+ for (AOTCompiledClass compiledClass : classes) {
+ if (compiledClass.hasCompiledMethods()) {
+ compiledClasses.add(compiledClass);
+ }
+ }
+ return compiledClasses;
+ }
+
+ /**
+ * Enqueue a method in the {@link #compileQueue}.
+ *
+ * @param method method to be enqueued
+ */
+ private void enqueueMethod(AOTCompiledClass aotClass, ResolvedJavaMethod method) {
+ AOTCompilationTask task = new AOTCompilationTask(main, graalOptions, aotClass, method, backend);
+ try {
+ compileQueue.execute(task);
+ } catch (RejectedExecutionException e) {
+ e.printStackTrace();
+ }
+ }
+
+ static void logCompilation(String methodName, String message) {
+ LogPrinter.writeLog(message + " " + methodName);
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTDynamicTypeStore.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTDynamicTypeStore.java
new file mode 100644
index 000000000..a8fb12048
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTDynamicTypeStore.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package jdk.tools.jaotc;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.graalvm.compiler.hotspot.meta.HotSpotInvokeDynamicPlugin.DynamicTypeStore;
+
+import jdk.vm.ci.hotspot.HotSpotConstantPool;
+import jdk.vm.ci.hotspot.HotSpotConstantPoolObject;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.JavaConstant;
+
+final class AOTDynamicTypeStore implements DynamicTypeStore {
+
+ public static class Location {
+ private HotSpotResolvedObjectType holder;
+ private int cpi;
+
+ Location(HotSpotResolvedObjectType holder, int cpi) {
+ this.holder = holder;
+ this.cpi = cpi;
+ }
+
+ public HotSpotResolvedObjectType getHolder() {
+ return holder;
+ }
+
+ public int getCpi() {
+ return cpi;
+ }
+
+ @Override
+ public String toString() {
+ return getHolder().getName() + "@" + cpi;
+ }
+
+ @Override
+ public int hashCode() {
+ return holder.hashCode() + getClass().hashCode() + cpi;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (getClass() != o.getClass()) {
+ return false;
+ }
+ Location l = (Location) o;
+ return cpi == l.cpi && holder.equals(l.holder);
+ }
+ }
+
+ public static class AdapterLocation extends Location {
+ private int methodId;
+
+ AdapterLocation(HotSpotResolvedObjectType holder, int cpi, int methodId) {
+ super(holder, cpi);
+ this.methodId = methodId;
+ }
+
+ public int getMethodId() {
+ return methodId;
+ }
+
+ @Override
+ public String toString() {
+ return "adapter:" + methodId + "@" + super.toString();
+ }
+ }
+
+ public static class AppendixLocation extends Location {
+ AppendixLocation(HotSpotResolvedObjectType holder, int cpi) {
+ super(holder, cpi);
+ }
+
+ @Override
+ public String toString() {
+ return "appendix@" + super.toString();
+ }
+ }
+
+ private HashMap<HotSpotResolvedObjectType, HashSet<Location>> typeMap = new HashMap<>();
+ private HashMap<HotSpotResolvedObjectType, HashSet<HotSpotResolvedObjectType>> holderMap = new HashMap<>();
+
+ public Set<HotSpotResolvedObjectType> getDynamicTypes() {
+ synchronized (typeMap) {
+ return typeMap.keySet();
+ }
+ }
+
+ public Set<HotSpotResolvedObjectType> getDynamicHolders() {
+ synchronized (holderMap) {
+ return holderMap.keySet();
+ }
+ }
+
+ @Override
+ public void recordAdapter(int opcode, HotSpotResolvedObjectType holder, int index, HotSpotResolvedJavaMethod adapter) {
+ int cpi = ((HotSpotConstantPool) holder.getConstantPool()).rawIndexToConstantPoolIndex(index, opcode);
+ int methodId = adapter.methodIdnum();
+ HotSpotResolvedObjectType adapterType = adapter.getDeclaringClass();
+ recordDynamicTypeLocation(new AdapterLocation(holder, cpi, methodId), adapterType);
+ }
+
+ @Override
+ public JavaConstant recordAppendix(int opcode, HotSpotResolvedObjectType holder, int index, JavaConstant appendix) {
+ int cpi = ((HotSpotConstantPool) holder.getConstantPool()).rawIndexToConstantPoolIndex(index, opcode);
+ HotSpotResolvedObjectType appendixType = ((HotSpotObjectConstant) appendix).getType();
+ recordDynamicTypeLocation(new AppendixLocation(holder, cpi), appendixType);
+ // Make the constant locatable
+ return HotSpotConstantPoolObject.forObject(holder, cpi, appendix);
+ }
+
+ private static <T> void recordDynamicMapValue(HashMap<HotSpotResolvedObjectType, HashSet<T>> map, HotSpotResolvedObjectType type, T v) {
+ synchronized (map) {
+ HashSet<T> set = map.get(type);
+ if (set == null) {
+ set = new HashSet<>();
+ map.put(type, set);
+ }
+ set.add(v);
+ }
+ }
+
+ private void recordDynamicTypeLocation(Location l, HotSpotResolvedObjectType type) {
+ recordDynamicMapValue(typeMap, type, l);
+ HotSpotResolvedObjectType holder = l.getHolder();
+ recordDynamicMapValue(holderMap, holder, type);
+ }
+
+ public Set<Location> getDynamicClassLocationsForType(HotSpotResolvedObjectType type) {
+ synchronized (typeMap) {
+ return typeMap.get(type);
+ }
+ }
+
+ public Set<HotSpotResolvedObjectType> getDynamicTypesForHolder(HotSpotResolvedObjectType holder) {
+ synchronized (holderMap) {
+ return holderMap.get(holder);
+ }
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java
new file mode 100644
index 000000000..0bad5d5c4
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
+import org.graalvm.compiler.options.OptionValues;
+
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+
+final class AOTHotSpotResolvedJavaMethod implements JavaMethodInfo {
+
+ private final HotSpotResolvedJavaMethod method;
+ private final Backend backend;
+ private final OptionValues options;
+
+ AOTHotSpotResolvedJavaMethod(HotSpotResolvedJavaMethod method, Backend backend, OptionValues options) {
+ this.method = method;
+ this.backend = backend;
+ this.options = options;
+ }
+
+ @Override
+ public String getSymbolName() {
+ return JavaMethodInfo.uniqueMethodName(method);
+ }
+
+ @Override
+ public String getNameAndSignature() {
+ String className = method.getDeclaringClass().getName();
+ return className + "." + method.getName() + method.getSignature().toMethodDescriptor();
+ }
+
+ @Override
+ public HotSpotCompiledCode compiledCode(CompilationResult result) {
+ return HotSpotCompiledCodeBuilder.createCompiledCode(backend.getCodeCache(), method, null, result, options);
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java
new file mode 100644
index 000000000..4848b8ef0
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+import org.graalvm.compiler.options.OptionValues;
+
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+
+final class AOTStub implements JavaMethodInfo {
+
+ private final Stub stub;
+ private final Backend backend;
+ private OptionValues options;
+
+ AOTStub(Stub stub, Backend backend, OptionValues options) {
+ this.stub = stub;
+ this.backend = backend;
+ this.options = options;
+ }
+
+ @Override
+ public String getSymbolName() {
+ return stub.toString();
+ }
+
+ @Override
+ public String getNameAndSignature() {
+ return stub.toString();
+ }
+
+ @Override
+ public HotSpotCompiledCode compiledCode(CompilationResult result) {
+ return HotSpotCompiledCodeBuilder.createCompiledCode(backend.getCodeCache(), null, null, result, options);
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallInfo.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallInfo.java
new file mode 100644
index 000000000..724618a3c
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallInfo.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import org.graalvm.compiler.bytecode.Bytecodes;
+import org.graalvm.compiler.hotspot.HotSpotMarkId;
+
+import jdk.vm.ci.code.BytecodePosition;
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+final class CallInfo {
+
+ static boolean isStaticTarget(Call call) {
+ return !((HotSpotResolvedJavaMethod) call.target).hasReceiver();
+ }
+
+ private static boolean isStaticOpcode(Call call) {
+ int opcode = getByteCode(call) & 0xFF;
+ return opcode == Bytecodes.INVOKESTATIC || opcode == Bytecodes.INVOKEDYNAMIC ||
+ opcode == Bytecodes.INVOKEVIRTUAL /* invokehandle */;
+ }
+
+ static boolean isStaticCall(Call call) {
+ if (isJavaCall(call) && isStaticTarget(call)) {
+ assert isStaticOpcode(call);
+ return true;
+ }
+ return false;
+ }
+
+ static boolean isSpecialCall(Call call) {
+ if (isJavaCall(call)) {
+ return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKESPECIAL);
+ }
+ return false;
+ }
+
+ private static boolean isInvokeVirtual(Call call) {
+ if (isJavaCall(call)) {
+ return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKEVIRTUAL) || ((getByteCode(call) & 0xFF) == Bytecodes.INVOKEINTERFACE);
+ }
+ return false;
+ }
+
+ static boolean isVirtualCall(CompiledMethodInfo methodInfo, Call call) {
+ return isInvokeVirtual(call) && !methodInfo.hasMark(call, HotSpotMarkId.INVOKESPECIAL) && !isStaticTarget(call);
+ }
+
+ static boolean isOptVirtualCall(CompiledMethodInfo methodInfo, Call call) {
+ return isInvokeVirtual(call) && methodInfo.hasMark(call, HotSpotMarkId.INVOKESPECIAL);
+ }
+
+ private static boolean isJavaCall(Call call) {
+ // If there is no associated debug info return false
+ if (call.debugInfo == null) {
+ return false;
+ }
+ BytecodePosition bcpos = call.debugInfo.getBytecodePosition();
+ ResolvedJavaMethod method = bcpos.getMethod();
+ // If bytecode position indicates a special value (negative value) it is
+ // not a normal java call
+ if (bcpos.getBCI() < 0) {
+ return false;
+ }
+ // If there is no method associated with the debuginfo, return false
+ if (method == null) {
+ return false;
+ }
+ assert (method instanceof HotSpotResolvedJavaMethod) : "Not a resolved Java call";
+ return true;
+ }
+
+ private static byte getByteCode(Call call) {
+ ResolvedJavaMethod m = call.debugInfo.getBytecodePosition().getMethod();
+ int callPosition = call.debugInfo.getBytecodePosition().getBCI();
+ byte[] code = m.getCode();
+ return code[callPosition];
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationInfo.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationInfo.java
new file mode 100644
index 000000000..3adc25a98
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationInfo.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+
+/**
+ * Describes a call site relocation. Contains a name of the callee and a relocation type, describing
+ * which relocation to use at the call site.
+ */
+abstract class CallSiteRelocationInfo {
+
+ final String targetSymbol;
+ final RelocType type;
+
+ CallSiteRelocationInfo(String targetSymbol, RelocType type) {
+ this.targetSymbol = targetSymbol;
+ this.type = type;
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java
new file mode 100644
index 000000000..c8de636b3
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.ByteContainer;
+import jdk.tools.jaotc.binformat.CodeContainer;
+import jdk.tools.jaotc.binformat.Relocation;
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+import jdk.tools.jaotc.binformat.Symbol;
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+
+/**
+ * Describes a relocation symbol of a call site. That is, WHERE to do a relocation.
+ */
+abstract class CallSiteRelocationSymbol {
+
+ final Symbol symbol;
+
+ CallSiteRelocationSymbol(Symbol symbol) {
+ assert symbol != null;
+ this.symbol = symbol;
+ }
+
+ protected static Symbol createCodeContainerSymbol(BinaryContainer binaryContainer, String symbolName, int symbolOffset) {
+ return binaryContainer.getCodeContainer().createSymbol(symbolOffset, Kind.OBJECT, Binding.LOCAL, 0, symbolName);
+ }
+
+ protected static void addCodeContainerRelocation(BinaryContainer binaryContainer, String symbolName, int symbolOffset, int relocationOffset) {
+ Symbol symbol = createCodeContainerSymbol(binaryContainer, symbolName, symbolOffset);
+ addExternalGotToPltRelocation(binaryContainer, symbol, relocationOffset);
+ }
+
+ protected static void addExtLinkageGotContainerRelocation(BinaryContainer binaryContainer, String symbolName, int symbolOffset, int relocationOffset) {
+ ByteContainer container = binaryContainer.getExtLinkageGOTContainer();
+ Symbol symbol = container.createGotSymbol(symbolOffset, symbolName);
+ addExternalPltToGotRelocation(binaryContainer, symbol, relocationOffset);
+ }
+
+ /**
+ * Add an {@link RelocType#EXTERNAL_GOT_TO_PLT} relocation to the
+ * {@link BinaryContainer#getExtLinkageGOTContainer()}.
+ */
+ private static void addExternalGotToPltRelocation(BinaryContainer binaryContainer, Symbol symbol, int relocationOffset) {
+ ByteContainer container = binaryContainer.getExtLinkageGOTContainer();
+ Relocation relocation = new Relocation(relocationOffset, RelocType.EXTERNAL_GOT_TO_PLT, 8, container, symbol);
+ binaryContainer.addRelocation(relocation);
+ }
+
+ /**
+ * Add an {@link RelocType#EXTERNAL_PLT_TO_GOT} relocation to the
+ * {@link BinaryContainer#getCodeContainer()}.
+ */
+ protected static void addExternalPltToGotRelocation(BinaryContainer binaryContainer, Symbol symbol, int relocationOffset) {
+ CodeContainer container = binaryContainer.getCodeContainer();
+ Relocation relocation = new Relocation(relocationOffset, RelocType.EXTERNAL_PLT_TO_GOT, 8, container, symbol);
+ binaryContainer.addRelocation(relocation);
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeOffsets.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeOffsets.java
new file mode 100644
index 000000000..a2c9c5125
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeOffsets.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import java.util.List;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.hotspot.HotSpotMarkId;
+
+final class CodeOffsets {
+ private final int entry;
+ private final int verifiedEntry;
+ private final int exceptionHandler;
+ private final int deoptHandler;
+ private final int deoptMHHandler;
+
+ private CodeOffsets(int entry, int verifiedEntry, int exceptionHandler, int deoptHandler, int deoptMHHandler) {
+ this.entry = entry;
+ this.verifiedEntry = verifiedEntry;
+ this.exceptionHandler = exceptionHandler;
+ this.deoptHandler = deoptHandler;
+ this.deoptMHHandler = deoptMHHandler;
+ }
+
+ static CodeOffsets buildFrom(List<CompilationResult.CodeMark> marks) {
+ int entry = 0;
+ int verifiedEntry = 0;
+ int exceptionHandler = -1;
+ int deoptHandler = -1;
+ int deoptMHHandler = -1;
+
+ for (CompilationResult.CodeMark mark : marks) {
+ HotSpotMarkId markId = (HotSpotMarkId) mark.id;
+ switch (markId) {
+ case UNVERIFIED_ENTRY:
+ entry = mark.pcOffset;
+ break;
+ case VERIFIED_ENTRY:
+ verifiedEntry = mark.pcOffset;
+ break;
+ case OSR_ENTRY:
+ // Unhandled
+ break;
+ case EXCEPTION_HANDLER_ENTRY:
+ exceptionHandler = mark.pcOffset;
+ break;
+ case DEOPT_HANDLER_ENTRY:
+ deoptHandler = mark.pcOffset;
+ break;
+ case DEOPT_MH_HANDLER_ENTRY:
+ deoptMHHandler = mark.pcOffset;
+ break;
+ default:
+ break; // Ignore others
+ }
+ }
+ return new CodeOffsets(entry, verifiedEntry, exceptionHandler, deoptHandler, deoptMHHandler);
+ }
+
+ int entry() {
+ return entry;
+ }
+
+ int verifiedEntry() {
+ return verifiedEntry;
+ }
+
+ int exceptionHandler() {
+ return exceptionHandler;
+ }
+
+ int deoptHandler() {
+ return deoptHandler;
+ }
+
+ int deoptMHHandler() {
+ return deoptMHHandler;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeSectionProcessor.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeSectionProcessor.java
new file mode 100644
index 000000000..ff5e9ca89
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeSectionProcessor.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import java.util.ArrayList;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.options.OptionValues;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.CodeContainer;
+import jdk.tools.jaotc.binformat.Symbol;
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.code.site.Infopoint;
+import jdk.vm.ci.code.site.InfopointReason;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+final class CodeSectionProcessor {
+
+ private final OptionValues optionValues;
+
+ private final TargetDescription target;
+
+ private final BinaryContainer binaryContainer;
+
+ CodeSectionProcessor(DataBuilder dataBuilder) {
+ this.target = dataBuilder.getBackend().getTarget();
+ this.binaryContainer = dataBuilder.getBinaryContainer();
+ this.optionValues = dataBuilder.getBackend().getRuntime().getOptions();
+ }
+
+ /**
+ * Method that looks at code section of a compiled result {@code compClass} and records function
+ * entry point symbols along with the text section contents. Note that the text section contents
+ * are not yet ready to be written in the form of a binary text section since the contents may
+ * need to be patched with references to other sections.
+ *
+ * @param compClass Graal compilation result.
+ */
+ void process(AOTCompiledClass compClass) {
+ ArrayList<CompiledMethodInfo> compiledMethods = compClass.getCompiledMethods();
+
+ for (CompiledMethodInfo methodInfo : compiledMethods) {
+ CompilationResult compResult = methodInfo.getCompilationResult();
+
+ byte[] targetCode = compResult.getTargetCode();
+ int targetCodeSize = compResult.getTargetCodeSize();
+ JavaMethodInfo compMethod = methodInfo.getMethodInfo();
+
+ // Step through all foreign calls, for every call, clear destination.
+ // Otherwise libelf may not patch them correctly.
+ for (Infopoint infopoint : compResult.getInfopoints()) {
+ if (infopoint.reason == InfopointReason.CALL) {
+ final Call callInfopoint = (Call) infopoint;
+ if (callInfopoint.target instanceof HotSpotForeignCallLinkage &&
+ target.arch instanceof AMD64) {
+ // TODO 4 is x86 size of relative displacement.
+ // For SPARC need something different.
+ int destOffset = infopoint.pcOffset + callInfopoint.size - 4;
+ targetCode[destOffset + 0] = 0;
+ targetCode[destOffset + 1] = 0;
+ targetCode[destOffset + 2] = 0;
+ targetCode[destOffset + 3] = 0;
+ }
+ }
+ }
+
+ String entry = compMethod.getSymbolName();
+ assert entry != null : "missing name for compiled method";
+
+ // Align and pad method entry
+ CodeContainer codeSection = binaryContainer.getCodeContainer();
+ int codeIdOffset = BinaryContainer.alignUp(codeSection, binaryContainer.getCodeSegmentSize());
+ // Store CodeId into code. It will be use by find_aot() using code.segments
+ methodInfo.setCodeId();
+ binaryContainer.appendIntToCode(methodInfo.getCodeId());
+ int textBaseOffset = BinaryContainer.alignUp(codeSection, binaryContainer.getCodeEntryAlignment());
+
+ codeSection.createSymbol(textBaseOffset, Symbol.Kind.JAVA_FUNCTION, Symbol.Binding.LOCAL, targetCodeSize, entry);
+
+ // Set the offset at which the text section of this method would be layed out
+ methodInfo.setTextSectionOffset(textBaseOffset);
+
+ // Write code bytes of the current method into byte stream
+ binaryContainer.appendCodeBytes(targetCode, 0, targetCodeSize);
+ int currentStubOffset = BinaryContainer.alignUp(codeSection, 8);
+ // Set the offset at which stubs of this method would be laid out
+ methodInfo.setStubsOffset(currentStubOffset - textBaseOffset);
+ // step through all calls, for every call, add a stub
+ for (Infopoint infopoint : compResult.getInfopoints()) {
+ if (infopoint.reason == InfopointReason.CALL) {
+ final Call callInfopoint = (Call) infopoint;
+ if (callInfopoint.target instanceof ResolvedJavaMethod) {
+ ResolvedJavaMethod call = (ResolvedJavaMethod) callInfopoint.target;
+ StubInformation stub = addCallStub(CallInfo.isVirtualCall(methodInfo, callInfopoint));
+ // Get the targetSymbol. A symbol for this will be created later during plt
+ // creation
+ String targetSymbol = JavaMethodInfo.uniqueMethodName(call) + ".at." + infopoint.pcOffset;
+ methodInfo.addStubCode(targetSymbol, stub);
+ currentStubOffset += stub.getSize();
+ }
+ }
+ }
+ assert currentStubOffset == codeSection.getByteStreamSize() : "wrong offset";
+ binaryContainer.addCodeSegments(codeIdOffset, currentStubOffset);
+ }
+ }
+
+ private StubInformation addCallStub(boolean isVirtualCall) {
+ final int startOffset = binaryContainer.getCodeContainer().getByteStreamSize();
+ StubInformation stub = new StubInformation(startOffset, isVirtualCall);
+ ELFMacroAssembler masm = ELFMacroAssembler.getELFMacroAssembler(target, optionValues);
+ byte[] code;
+ if (isVirtualCall) {
+ code = masm.getPLTVirtualEntryCode(stub);
+ } else {
+ code = masm.getPLTStaticEntryCode(stub);
+ }
+ binaryContainer.appendCodeBytes(code, 0, code.length);
+ return stub;
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Collector.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Collector.java
new file mode 100644
index 000000000..bd127b308
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Collector.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import jdk.tools.jaotc.collect.ClassSearch;
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider;
+import jdk.tools.jaotc.collect.directory.DirectorySourceProvider;
+import jdk.tools.jaotc.collect.jar.JarSourceProvider;
+import jdk.tools.jaotc.collect.module.ModuleSourceProvider;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+final class Collector {
+
+ private final Main main;
+
+ Collector(Main main) {
+ this.main = main;
+ }
+
+ Set<Class<?>> collectClassesToCompile() {
+ Set<Class<?>> classesToCompile = new HashSet<>();
+ FileSupport fileSupport = new FileSupport();
+ ClassSearch lookup = new ClassSearch();
+ lookup.addProvider(new ModuleSourceProvider());
+ lookup.addProvider(new ClassNameSourceProvider(fileSupport));
+ lookup.addProvider(new JarSourceProvider());
+ lookup.addProvider(new DirectorySourceProvider(fileSupport));
+
+ List<LoadedClass> foundClasses = null;
+ try {
+ foundClasses = lookup.search(main.options.files, main.options.searchPath, this::handleLoadingError);
+ } catch (InternalError e) {
+ main.printer.reportError(e);
+ return null;
+ }
+
+ for (LoadedClass loadedClass : foundClasses) {
+ classesToCompile.add(loadedClass.getLoadedClass());
+ }
+ return classesToCompile;
+ }
+
+ private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions) {
+ for (ResolvedJavaMethod m : methods) {
+ addMethod(aotClass, m, compilationRestrictions);
+ }
+ }
+
+ private void addMethod(AOTCompiledClass aotClass, ResolvedJavaMethod method, CompilationSpec compilationRestrictions) {
+ // Don't compile native or abstract methods.
+ if (!method.hasBytecodes()) {
+ return;
+ }
+ if (!compilationRestrictions.shouldCompileMethod(method)) {
+ return;
+ }
+ if (!main.filters.shouldCompileMethod(method)) {
+ return;
+ }
+ assert ((HotSpotResolvedObjectType) method.getDeclaringClass()).getFingerprint() != 0 : "no fingerprint for " + method.getDeclaringClass().getName();
+
+ aotClass.addMethod(method);
+ main.printer.printlnVerbose(" added " + method.getName() + method.getSignature().toMethodDescriptor());
+ }
+
+ /**
+ * Collect all method we should compile.
+ *
+ * @return array list of AOT classes which have compiled methods.
+ */
+ List<AOTCompiledClass> collectMethodsToCompile(Set<Class<?>> classesToCompile, MetaAccessProvider metaAccess) {
+ int total = 0;
+ int count = 0;
+ List<AOTCompiledClass> classes = new ArrayList<>();
+ CompilationSpec compilationRestrictions = collectSpecifiedMethods();
+
+ for (Class<?> c : classesToCompile) {
+ ResolvedJavaType resolvedJavaType = metaAccess.lookupJavaType(c);
+ if (main.filters.shouldCompileAnyMethodInClass(resolvedJavaType)) {
+ AOTCompiledClass aotClass = new AOTCompiledClass(resolvedJavaType);
+ main.printer.printlnVerbose(" Scanning " + c.getName());
+
+ // Constructors
+ try {
+ ResolvedJavaMethod[] ctors = resolvedJavaType.getDeclaredConstructors();
+ addMethods(aotClass, ctors, compilationRestrictions);
+ total += ctors.length;
+ } catch (Throwable e) {
+ handleLoadingError(c.getName(), e);
+ }
+
+ // Methods
+ try {
+ ResolvedJavaMethod[] methods = resolvedJavaType.getDeclaredMethods();
+ addMethods(aotClass, methods, compilationRestrictions);
+ total += methods.length;
+ } catch (Throwable e) {
+ handleLoadingError(c.getName(), e);
+ }
+
+ // Class initializer
+ try {
+ ResolvedJavaMethod clinit = resolvedJavaType.getClassInitializer();
+ if (clinit != null) {
+ addMethod(aotClass, clinit, compilationRestrictions);
+ total++;
+ }
+ } catch (Throwable e) {
+ handleLoadingError(c.getName(), e);
+ }
+
+ // Found any methods to compile? Add the class.
+ if (aotClass.hasMethods()) {
+ classes.add(aotClass);
+ count += aotClass.getMethodCount();
+ }
+ }
+ }
+ main.printer.printInfo(total + " methods total, " + count + " methods to compile");
+ return classes;
+ }
+
+ /**
+ * If a file with compilation limitations is specified using flag --compile-commands, read the
+ * file's contents and collect the restrictions.
+ */
+ private CompilationSpec collectSpecifiedMethods() {
+ CompilationSpec compilationRestrictions = new CompilationSpec();
+ String methodListFileName = main.options.methodList;
+
+ if (methodListFileName != null && !methodListFileName.equals("")) {
+ try {
+ FileReader methListFile = new FileReader(methodListFileName);
+ BufferedReader readBuf = new BufferedReader(methListFile);
+ String line = null;
+ while ((line = readBuf.readLine()) != null) {
+ String trimmedLine = line.trim();
+ if (!trimmedLine.startsWith("#")) {
+ String[] components = trimmedLine.split(" ");
+ if (components.length == 2) {
+ String directive = components[0];
+ String pattern = components[1];
+ switch (directive) {
+ case "compileOnly":
+ compilationRestrictions.addCompileOnlyPattern(pattern);
+ break;
+ case "exclude":
+ compilationRestrictions.addExcludePattern(pattern);
+ break;
+ default:
+ System.out.println("Unrecognized command " + directive + ". Ignoring\n\t" + line + "\n encountered in " + methodListFileName);
+ }
+ } else {
+ if (!trimmedLine.equals("")) {
+ System.out.println("Ignoring malformed line:\n\t " + line + "\n");
+ }
+ }
+ }
+ }
+ readBuf.close();
+ } catch (FileNotFoundException e) {
+ throw new InternalError("Unable to open method list file: " + methodListFileName, e);
+ } catch (IOException e) {
+ throw new InternalError("Unable to read method list file: " + methodListFileName, e);
+ }
+ }
+
+ return compilationRestrictions;
+ }
+
+ private void handleLoadingError(String name, Throwable t) {
+ if (main.options.ignoreClassLoadingErrors) {
+ main.printer.printError(name + ": " + t);
+ } else {
+ throw new InternalError(t);
+ }
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompilationSpec.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompilationSpec.java
new file mode 100644
index 000000000..19662c52b
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompilationSpec.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.regex.Pattern;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * A class encapsulating any user-specified compilation restrictions.
+ */
+final class CompilationSpec {
+
+ /**
+ * Set of method names to restrict compilation to.
+ */
+ private HashSet<String> compileOnlyStrings = new HashSet<>();
+ private HashSet<Pattern> compileOnlyPatterns = new HashSet<>();
+
+ /**
+ * Set of method names that should be excluded from compilation.
+ */
+ private HashSet<String> excludeStrings = new HashSet<>();
+ private HashSet<Pattern> excludePatterns = new HashSet<>();
+
+ /**
+ * Add a {@code compileOnly} directive to the compile-only list.
+ *
+ * @param pattern regex or non-regex pattern string
+ */
+ void addCompileOnlyPattern(String pattern) {
+ if (pattern.contains("*")) {
+ compileOnlyPatterns.add(Pattern.compile(pattern));
+ } else {
+ compileOnlyStrings.add(pattern);
+ }
+ }
+
+ /**
+ * Add an {@code exclude} directive to the exclude list.
+ *
+ * @param pattern regex or non-regex pattern string
+ */
+ void addExcludePattern(String pattern) {
+ if (pattern.contains("*")) {
+ excludePatterns.add(Pattern.compile(pattern));
+ } else {
+ excludeStrings.add(pattern);
+ }
+ }
+
+ /**
+ * Check if a given method is part of a restrictive compilation.
+ *
+ * @param method method to be checked
+ * @return true or false
+ */
+ boolean shouldCompileMethod(ResolvedJavaMethod method) {
+ if (compileWithRestrictions()) {
+ // If there are user-specified compileOnly patterns, default action
+ // is not to compile the method.
+ boolean compileMethod = compileOnlyStrings.isEmpty() && compileOnlyPatterns.isEmpty();
+
+ // Check if the method matches with any of the specified compileOnly patterns.
+ String methodName = JavaMethodInfo.uniqueMethodName(method);
+
+ // compileOnly
+ if (!compileMethod) {
+ compileMethod = compileOnlyStrings.contains(methodName);
+ }
+ if (!compileMethod) {
+ Iterator<Pattern> it = compileOnlyPatterns.iterator();
+ while (!compileMethod && it.hasNext()) {
+ Pattern pattern = it.next();
+ compileMethod = pattern.matcher(methodName).matches();
+ }
+ }
+
+ // exclude
+ if (compileMethod) {
+ compileMethod = !excludeStrings.contains(methodName);
+ }
+ if (compileMethod) {
+ Iterator<Pattern> it = excludePatterns.iterator();
+ while (compileMethod && it.hasNext()) {
+ Pattern pattern = it.next();
+ compileMethod = !(pattern.matcher(methodName).matches());
+ }
+ }
+ return compileMethod;
+ }
+ return true;
+ }
+
+ /**
+ * Return true if compilation restrictions are specified.
+ */
+ private boolean compileWithRestrictions() {
+ return !(compileOnlyStrings.isEmpty() && compileOnlyPatterns.isEmpty() && excludeStrings.isEmpty() && excludePatterns.isEmpty());
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java
new file mode 100644
index 000000000..49db6afbb
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.hotspot.HotSpotMarkId;
+
+import jdk.tools.jaotc.AOTCompiledClass.AOTKlassData;
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+
+final class CompiledMethodInfo {
+
+ static final String archStr = System.getProperty("os.arch").toLowerCase();
+
+ private static final int UNINITIALIZED_OFFSET = -1;
+
+ private static class AOTMethodOffsets {
+ /**
+ * Offset in metaspace names section.
+ */
+ private int nameOffset;
+
+ /**
+ * Offset in the text section at which compiled code starts.
+ */
+ private int textSectionOffset;
+
+ /**
+ * Offset in the metadata section.
+ */
+ private int metadataOffset;
+
+ /**
+ * Offset to the metadata in the GOT table.
+ */
+ private int metadataGotOffset;
+
+ /**
+ * Size of the metadata.
+ */
+ private int metadataGotSize;
+
+ /**
+ * The sequential number corresponding to the order of methods code in code buffer.
+ */
+ private int codeId;
+
+ AOTMethodOffsets() {
+ this.nameOffset = UNINITIALIZED_OFFSET;
+ this.textSectionOffset = UNINITIALIZED_OFFSET;
+ this.metadataOffset = UNINITIALIZED_OFFSET;
+ this.metadataGotOffset = UNINITIALIZED_OFFSET;
+ this.metadataGotSize = -1;
+ this.codeId = -1;
+ }
+
+ void addMethodOffsets(ReadOnlyDataContainer container, String name) {
+ verify(name);
+ // @formatter:off
+ /*
+ * The offsets layout should match AOTMethodOffsets structure in AOT JVM runtime
+ */
+ // Add the offset to the name in the .metaspace.names section
+ container.appendInt(nameOffset).
+ // Add the offset to the code in the .text section
+ appendInt(textSectionOffset).
+ // Add the offset to the metadata in the .method.metadata section
+ appendInt(metadataOffset).
+ // Add the offset to the metadata in the .metadata.got section
+ appendInt(metadataGotOffset).
+ // Add the size of the metadata
+ appendInt(metadataGotSize).
+ // Add code ID.
+ appendInt(codeId);
+ // @formatter:on
+ }
+
+ private void verify(String name) {
+ assert nameOffset >= 0 : "incorrect nameOffset: " + nameOffset + " for method: " + name;
+ assert textSectionOffset > 0 : "incorrect textSectionOffset: " + textSectionOffset + " for method: " + name;
+ assert metadataOffset >= 0 : "incorrect metadataOffset: " + metadataOffset + " for method: " + name;
+ assert metadataGotOffset >= 0 : "incorrect metadataGotOffset: " + metadataGotOffset + " for method: " + name;
+ assert metadataGotSize >= 0 : "incorrect metadataGotSize: " + metadataGotSize + " for method: " + name;
+ assert codeId >= 0 : "incorrect codeId: " + codeId + " for method: " + name;
+ }
+
+ protected void setNameOffset(int offset) {
+ nameOffset = offset;
+ }
+
+ protected void setTextSectionOffset(int textSectionOffset) {
+ this.textSectionOffset = textSectionOffset;
+ }
+
+ protected int getTextSectionOffset() {
+ return textSectionOffset;
+ }
+
+ protected void setCodeId(int codeId) {
+ this.codeId = codeId;
+ }
+
+ protected int getCodeId() {
+ return codeId;
+ }
+
+ protected void setMetadataOffset(int offset) {
+ metadataOffset = offset;
+ }
+
+ protected void setMetadataGotOffset(int metadataGotOffset) {
+ this.metadataGotOffset = metadataGotOffset;
+ }
+
+ protected void setMetadataGotSize(int length) {
+ this.metadataGotSize = length;
+ }
+ }
+
+ /**
+ * Method name.
+ */
+ private String name;
+
+ /**
+ * Result of graal compilation.
+ */
+ private CompilationResult compilationResult;
+
+ /**
+ * HotSpotResolvedJavaMethod or Stub corresponding to the compilation result.
+ */
+ private JavaMethodInfo methodInfo;
+
+ /**
+ * Compiled code from installation.
+ */
+ private HotSpotCompiledCode code;
+
+ /**
+ * Offset to stubs.
+ */
+ private int stubsOffset;
+
+ /**
+ * The total size in bytes of the stub section.
+ */
+ private int totalStubSize;
+
+ /**
+ * Method's offsets.
+ */
+ private AOTMethodOffsets methodOffsets;
+
+ /**
+ * List of stubs (PLT trampoline).
+ */
+ private HashMap<String, StubInformation> stubs = new HashMap<>();
+
+ /**
+ * List of referenced classes.
+ */
+ private HashSet<AOTKlassData> dependentKlasses = new HashSet<>();
+
+ /**
+ * Methods count used to generate unique global method id.
+ */
+ private static final AtomicInteger methodsCount = new AtomicInteger();
+
+ CompiledMethodInfo(CompilationResult compilationResult, JavaMethodInfo methodInfo) {
+ this.name = methodInfo.getNameAndSignature();
+ this.compilationResult = compilationResult;
+ this.methodInfo = methodInfo;
+ this.stubsOffset = UNINITIALIZED_OFFSET;
+ this.methodOffsets = new AOTMethodOffsets();
+ }
+
+ String name() {
+ return name;
+ }
+
+ void addMethodOffsets(BinaryContainer binaryContainer, ReadOnlyDataContainer container) {
+ this.methodOffsets.setNameOffset(binaryContainer.addMetaspaceName(name));
+ this.methodOffsets.addMethodOffsets(container, name);
+ for (AOTKlassData data : dependentKlasses) {
+ data.addDependentMethod(this);
+ }
+ }
+
+ CompilationResult getCompilationResult() {
+ return compilationResult;
+ }
+
+ JavaMethodInfo getMethodInfo() {
+ return methodInfo;
+ }
+
+ void setTextSectionOffset(int textSectionOffset) {
+ methodOffsets.setTextSectionOffset(textSectionOffset);
+ }
+
+ public int getTextSectionOffset() {
+ return methodOffsets.getTextSectionOffset();
+ }
+
+ void setCodeId() {
+ methodOffsets.setCodeId(CompiledMethodInfo.getNextCodeId());
+ }
+
+ int getCodeId() {
+ return this.methodOffsets.getCodeId();
+ }
+
+ static int getMethodsCount() {
+ return methodsCount.get();
+ }
+
+ static int getNextCodeId() {
+ return methodsCount.getAndIncrement();
+ }
+
+ int getCodeSize() {
+ return stubsOffset + getStubCodeSize();
+ }
+
+ int getStubCodeSize() {
+ return totalStubSize;
+ }
+
+ void setMetadataOffset(int offset) {
+ this.methodOffsets.setMetadataOffset(offset);
+ }
+
+ /**
+ * Offset into the code of this method where the stub section starts.
+ */
+ void setStubsOffset(int offset) {
+ stubsOffset = offset;
+ }
+
+ int getStubsOffset() {
+ return stubsOffset;
+ }
+
+ void setMetadataGotOffset(int metadataGotOffset) {
+ this.methodOffsets.setMetadataGotOffset(metadataGotOffset);
+ }
+
+ void setMetadataGotSize(int length) {
+ this.methodOffsets.setMetadataGotSize(length);
+ }
+
+ void addStubCode(String call, StubInformation stub) {
+ stubs.put(call, stub);
+ totalStubSize += stub.getSize();
+ }
+
+ StubInformation getStubFor(String call) {
+ StubInformation stub = stubs.get(call);
+ assert stub != null : "missing stub for call " + call;
+ stub.verify();
+ return stub;
+ }
+
+ void addDependentKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) {
+ AOTKlassData klassData = AOTCompiledClass.addFingerprintKlassData(binaryContainer, type);
+ dependentKlasses.add(klassData);
+ }
+
+ AOTKlassData getDependentKlassData(HotSpotResolvedObjectType type) {
+ AOTKlassData klassData = AOTCompiledClass.getAOTKlassData(type);
+ if (dependentKlasses.contains(klassData)) {
+ return klassData;
+ }
+ return null;
+ }
+
+ boolean hasMark(Call call, HotSpotMarkId id) {
+ assert id == HotSpotMarkId.INVOKESTATIC || id == HotSpotMarkId.INVOKESPECIAL;
+ CompilationResult.CodeMark mark = compilationResult.getAssociatedMark(call);
+ if (mark != null) {
+ return mark.id == id;
+ }
+ return false;
+ }
+
+ String asTag() {
+ return "[" + methodInfo.getSymbolName() + "]";
+ }
+
+ HotSpotCompiledCode compiledCode() {
+ if (code == null) {
+ code = methodInfo.compiledCode(compilationResult);
+ }
+ return code;
+ }
+
+ // Free memory
+ void clear() {
+ this.dependentKlasses = null;
+ this.name = null;
+ }
+
+ void clearCompileData() {
+ this.code = null;
+ this.stubs = null;
+ this.compilationResult = null;
+ this.methodInfo = null;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java
new file mode 100644
index 000000000..949124ffe
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.hotspot.HotSpotHostBackend;
+import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.ByteContainer;
+import jdk.tools.jaotc.binformat.HeaderContainer;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
+import jdk.vm.ci.hotspot.VMField;
+
+final class DataBuilder {
+
+ private final Main main;
+
+ private final HotSpotHostBackend backend;
+
+ private final List<AOTCompiledClass> classes;
+
+ /**
+ * Target-independent container in which text symbols and code bytes are created.
+ */
+ private final BinaryContainer binaryContainer;
+
+ private static final HashMap<Long, String> vmAddresses = new HashMap<>();
+
+ DataBuilder(Main main, HotSpotHostBackend backend, List<AOTCompiledClass> classes, BinaryContainer binaryContainer) {
+ this.main = main;
+ this.backend = backend;
+ this.classes = classes;
+ this.binaryContainer = binaryContainer;
+ fillVMAddresses(HotSpotJVMCIRuntime.runtime().getConfigStore());
+ }
+
+ /**
+ * Returns a value-name map of all {@link VMField} fields.
+ */
+ private static void fillVMAddresses(HotSpotVMConfigStore config) {
+ for (VMField vmField : config.getFields().values()) {
+ if (vmField.value != null && vmField.value instanceof Long) {
+ final long address = (Long) vmField.value;
+ String value = vmField.name;
+ /*
+ * Some fields don't contain addresses but integer values. At least don't add zero
+ * entries to avoid matching null addresses.
+ */
+ if (address != 0) {
+ vmAddresses.put(address, value);
+ }
+ }
+ }
+ for (Entry<String, Long> vmAddress : config.getAddresses().entrySet()) {
+ final long address = vmAddress.getValue();
+ String value = vmAddress.getKey();
+ String old = vmAddresses.put(address, value);
+ if (old != null) {
+ throw new InternalError("already in map: address: " + address + ", current: " + value + ", old: " + old);
+ }
+ }
+ }
+
+ /**
+ * Get the C/C++ function name associated with the foreign call target {@code address}.
+ *
+ * @param address native address
+ * @return C/C++ functio name associated with the native address
+ */
+ static String getVMFunctionNameForAddress(long address) {
+ return vmAddresses.get(address);
+ }
+
+ /**
+ * Returns the host backend used for this compilation.
+ *
+ * @return host backend
+ */
+ HotSpotHostBackend getBackend() {
+ return backend;
+ }
+
+ /**
+ * Returns the binary container for this compilation.
+ *
+ * @return binary container
+ */
+ BinaryContainer getBinaryContainer() {
+ return binaryContainer;
+ }
+
+ /**
+ * Prepare data with all compiled classes and stubs.
+ *
+ * @param debug
+ *
+ * @throws Exception
+ */
+ @SuppressWarnings("try")
+ void prepareData(DebugContext debug) throws Exception {
+ try (Timer t = new Timer(main, "Parsing compiled code")) {
+ /*
+ * Copy compiled code into code section container and calls stubs (PLT trampoline).
+ */
+ CodeSectionProcessor codeSectionProcessor = new CodeSectionProcessor(this);
+ for (AOTCompiledClass c : classes) {
+ // For each class we need 2 GOT slots:
+ // first - for initialized klass
+ // second - only for loaded klass
+ c.addAOTKlassData(binaryContainer);
+ codeSectionProcessor.process(c);
+ }
+ }
+
+ AOTCompiledClass stubCompiledCode = retrieveStubCode(debug);
+
+ // Free memory!
+ try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) {
+ main.printer.printMemoryUsage();
+ System.gc();
+ }
+
+ MetadataBuilder metadataBuilder = null;
+ try (Timer t = new Timer(main, "Processing metadata")) {
+ /*
+ * Generate metadata for compiled code and copy it into metadata section. Create
+ * relocation information for all references (call, constants, etc) in compiled code.
+ */
+ metadataBuilder = new MetadataBuilder(this);
+ metadataBuilder.processMetadata(classes, stubCompiledCode);
+ }
+
+ // Free memory!
+ try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) {
+ main.printer.printMemoryUsage();
+ System.gc();
+ }
+
+ try (Timer t = new Timer(main, "Preparing stubs binary")) {
+ prepareStubsBinary(stubCompiledCode);
+ }
+ try (Timer t = new Timer(main, "Preparing compiled binary")) {
+ // Should be called after Stubs because they can set dependent klasses.
+ prepareCompiledBinary();
+ }
+ }
+
+ /**
+ * Get all stubs from Graal and add them to the code section.
+ *
+ * @param debug
+ */
+ @SuppressWarnings("try")
+ private AOTCompiledClass retrieveStubCode(DebugContext debug) {
+ ArrayList<CompiledMethodInfo> stubs = new ArrayList<>();
+ HotSpotForeignCallsProvider foreignCallsProvider = backend.getProviders().getForeignCalls();
+ for (Stub stub : foreignCallsProvider.getStubs()) {
+ try (DebugContext.Scope scope = debug.scope("CompileStubs")) {
+ CompilationResult result = stub.getCompilationResult(debug, backend);
+ CompiledMethodInfo cm = new CompiledMethodInfo(result, new AOTStub(stub, backend, debug.getOptions()));
+ stubs.add(cm);
+ } catch (Throwable e) {
+ throw debug.handle(e);
+ }
+ }
+ AOTCompiledClass stubCompiledCode = new AOTCompiledClass(stubs);
+ CodeSectionProcessor codeSectionProcessor = new CodeSectionProcessor(this);
+ codeSectionProcessor.process(stubCompiledCode);
+ return stubCompiledCode;
+ }
+
+ /**
+ * Prepare metaspace.offsets section.
+ */
+ private void prepareCompiledBinary() {
+ for (AOTCompiledClass c : classes) {
+ // Create records for compiled AOT methods.
+ c.putMethodsData(binaryContainer);
+ }
+ // Create records for compiled AOT classes.
+ AOTCompiledClass.putAOTKlassData(binaryContainer);
+
+ // Fill in AOTHeader
+ HeaderContainer header = binaryContainer.getHeaderContainer();
+ header.setClassesCount(AOTCompiledClass.getClassesCount());
+ header.setMethodsCount(CompiledMethodInfo.getMethodsCount());
+ // Record size of got sections
+ ByteContainer bc = binaryContainer.getKlassesGotContainer();
+ header.setKlassesGotSize((bc.getByteStreamSize() / 8));
+ bc = binaryContainer.getMetadataGotContainer();
+ header.setMetadataGotSize((bc.getByteStreamSize() / 8));
+ bc = binaryContainer.getOopGotContainer();
+ header.setOopGotSize((bc.getByteStreamSize() / 8));
+ }
+
+ /**
+ * Prepare stubs.offsets section.
+ */
+ private void prepareStubsBinary(AOTCompiledClass compiledClass) {
+ // For each of the compiled stubs, create records holding information about
+ // them.
+ ArrayList<CompiledMethodInfo> compiledStubs = compiledClass.getCompiledMethods();
+ int cntStubs = compiledStubs.size();
+ BinaryContainer.addMethodsCount(cntStubs, binaryContainer.getStubsOffsetsContainer());
+ for (CompiledMethodInfo methodInfo : compiledStubs) {
+ // Note, stubs have different offsets container.
+ methodInfo.addMethodOffsets(binaryContainer, binaryContainer.getStubsOffsetsContainer());
+ }
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java
new file mode 100644
index 000000000..c6b141b1f
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.graalvm.compiler.code.DataSection;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Relocation;
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+import jdk.tools.jaotc.binformat.Symbol;
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.code.site.ConstantReference;
+import jdk.vm.ci.code.site.DataPatch;
+import jdk.vm.ci.code.site.DataSectionReference;
+import jdk.vm.ci.code.site.Reference;
+import jdk.vm.ci.hotspot.HotSpotConstantPoolObject;
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.hotspot.HotSpotSentinelConstant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.VMConstant;
+
+final class DataPatchProcessor {
+
+ private final TargetDescription target;
+
+ private final BinaryContainer binaryContainer;
+
+ DataPatchProcessor(DataBuilder dataBuilder) {
+ this.target = dataBuilder.getBackend().getTarget();
+ this.binaryContainer = dataBuilder.getBinaryContainer();
+ }
+
+ /**
+ * Process a {@link DataPatch} generated by the compiler and create all needed binary section
+ * constructs.
+ */
+ void process(CompiledMethodInfo methodInfo, DataPatch dataPatch) {
+ Reference reference = dataPatch.reference;
+ if (reference instanceof ConstantReference) {
+ processConstantReference(dataPatch, methodInfo);
+ } else if (reference instanceof DataSectionReference) {
+ processDataSectionReference(dataPatch, methodInfo);
+ } else {
+ throw new InternalError("Unknown data patch reference: " + reference);
+ }
+ }
+
+ private void processConstantReference(DataPatch dataPatch, CompiledMethodInfo methodInfo) {
+ HotSpotConstantLoadAction action = (HotSpotConstantLoadAction) dataPatch.note;
+ ConstantReference constantReference = (ConstantReference) dataPatch.reference;
+ assert action != null : "action should be set";
+
+ VMConstant constant = constantReference.getConstant();
+ String targetSymbol = null;
+ String gotName = null;
+ if (constant instanceof HotSpotMetaspaceConstant) {
+ HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) constant;
+ if (metaspaceConstant.asResolvedJavaType() != null) {
+ HotSpotResolvedObjectType type = metaspaceConstant.asResolvedJavaType();
+ methodInfo.addDependentKlassData(binaryContainer, type);
+ targetSymbol = AOTCompiledClass.metadataName(type);
+ gotName = ((action == HotSpotConstantLoadAction.INITIALIZE) ? "got.init." : "got.") + targetSymbol;
+ } else if (metaspaceConstant.asResolvedJavaMethod() != null && action == HotSpotConstantLoadAction.LOAD_COUNTERS) {
+ targetSymbol = "counters." + JavaMethodInfo.uniqueMethodName(metaspaceConstant.asResolvedJavaMethod());
+ gotName = "got." + targetSymbol;
+ binaryContainer.addCountersSymbol(targetSymbol);
+ }
+ } else if (constant instanceof JavaConstant) {
+ JavaConstant jConstant = (JavaConstant) constant;
+ if (jConstant instanceof HotSpotConstantPoolObject) {
+ HotSpotConstantPoolObject cpo = (HotSpotConstantPoolObject) jConstant;
+ // Even if two locations use the same object, resolve separately
+ targetSymbol = "ldc." + cpo.toValueString();
+ Integer offset = binaryContainer.addOopSymbol(targetSymbol);
+ gotName = "got.ldc." + offset;
+ } else if (jConstant instanceof HotSpotObjectConstant) {
+ HotSpotObjectConstant oopConstant = (HotSpotObjectConstant) jConstant;
+ // String constant.
+ targetSymbol = "ldc." + oopConstant.toValueString();
+ Integer offset = binaryContainer.addOopSymbol(targetSymbol);
+ gotName = "got.ldc." + offset;
+ } else if (jConstant instanceof HotSpotSentinelConstant) {
+ targetSymbol = "state.M" + methodInfo.getCodeId();
+ gotName = "got." + targetSymbol;
+ }
+ }
+
+ assert gotName != null : "Unknown constant type: " + constant;
+
+ InstructionDecoder decoder = InstructionDecoder.getInstructionDecoder(target);
+ decoder.decodePosition(methodInfo.getCompilationResult().getTargetCode(), dataPatch.pcOffset);
+ int instructionEndOffset = decoder.currentEndOfInstruction();
+
+ int textBaseOffset = methodInfo.getTextSectionOffset();
+ int relocOffset = textBaseOffset + instructionEndOffset;
+
+ Symbol relocationSymbol = binaryContainer.getSymbol(gotName);
+ assert relocationSymbol != null : "symbol for " + gotName + " missing";
+ Relocation reloc = new Relocation(relocOffset, RelocType.METASPACE_GOT_REFERENCE, 0, binaryContainer.getCodeContainer(), relocationSymbol);
+ binaryContainer.addRelocation(reloc);
+ }
+
+ private void processDataSectionReference(DataPatch dataPatch, CompiledMethodInfo methodInfo) {
+ DataSectionReference dataReference = (DataSectionReference) dataPatch.reference;
+
+ InstructionDecoder decoder = InstructionDecoder.getInstructionDecoder(target);
+ decoder.decodePosition(methodInfo.getCompilationResult().getTargetCode(), dataPatch.pcOffset);
+ int instructionEndOffset = decoder.currentEndOfInstruction();
+
+ int textBaseOffset = methodInfo.getTextSectionOffset();
+ int relocOffset = textBaseOffset + instructionEndOffset;
+ int dataOffset = dataReference.getOffset();
+
+ DataSection dataSection = methodInfo.getCompilationResult().getDataSection();
+ DataSection.Data data = dataSection.findData(dataReference);
+ int size = data.getSize();
+ int alignment = data.getAlignment();
+ byte[] value = new byte[size];
+ ByteBuffer buffer = ByteBuffer.wrap(value).order(ByteOrder.nativeOrder());
+ DataSection.emit(buffer, data, (p, c) -> {
+ });
+ String targetSymbol = "data.M" + methodInfo.getCodeId() + "." + dataOffset;
+ Symbol relocationSymbol = binaryContainer.getSymbol(targetSymbol);
+ if (relocationSymbol == null) {
+ int symSize = Math.max(8, size);
+ int symAlig = Math.max(8, alignment);
+ int offsetInConstantDataSection = binaryContainer.addConstantData(value, symAlig);
+ relocationSymbol = binaryContainer.getConstantDataContainer().createSymbol(offsetInConstantDataSection, Kind.OBJECT, Binding.LOCAL, symSize, targetSymbol);
+ }
+ Relocation reloc = new Relocation(relocOffset, RelocType.METASPACE_GOT_REFERENCE, 0, binaryContainer.getCodeContainer(), relocationSymbol);
+ binaryContainer.addRelocation(reloc);
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ELFMacroAssembler.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ELFMacroAssembler.java
new file mode 100644
index 000000000..f305e5ee1
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ELFMacroAssembler.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import org.graalvm.compiler.options.OptionValues;
+
+import jdk.tools.jaotc.aarch64.AArch64ELFMacroAssembler;
+import jdk.tools.jaotc.amd64.AMD64ELFMacroAssembler;
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.TargetDescription;
+
+public interface ELFMacroAssembler {
+
+ static ELFMacroAssembler getELFMacroAssembler(TargetDescription target, OptionValues optionValues) {
+ Architecture architecture = target.arch;
+ if (architecture instanceof AMD64) {
+ return new AMD64ELFMacroAssembler(target, optionValues);
+ } else if (architecture instanceof AArch64) {
+ return new AArch64ELFMacroAssembler(target);
+ } else {
+ throw new InternalError("Unsupported architecture " + architecture);
+ }
+ }
+
+ int currentEndOfInstruction();
+
+ byte[] getPLTJumpCode();
+
+ byte[] getPLTStaticEntryCode(StubInformation stub);
+
+ byte[] getPLTVirtualEntryCode(StubInformation stub);
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationInfo.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationInfo.java
new file mode 100644
index 000000000..f7a5b7f8a
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationInfo.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+
+import jdk.vm.ci.code.site.Call;
+
+/**
+ * This is a foreign call site. This means either a call to the VM or a call to a Graal stub. If
+ * it's a call directly to the VM, mangle the name. The call should go through regular .plt used by
+ * the system loader, at least for now. If it's a call to a Graal stub, it should always be a direct
+ * call, since the Graal stubs are contained within the .so file.
+ */
+final class ForeignCallSiteRelocationInfo extends CallSiteRelocationInfo {
+
+ ForeignCallSiteRelocationInfo(Call call, HotSpotForeignCallLinkage callTarget) {
+ super(getTargetSymbol(call, callTarget), getRelocType(callTarget));
+ }
+
+ private static String getTargetSymbol(Call call, HotSpotForeignCallLinkage callTarget) {
+ // If it specifies a foreign call linkage, find the symbol corresponding to the address in
+ // HotSpotVMConfig's fields.
+ final long foreignCallTargetAddress = callTarget.getAddress();
+
+ // Get the C/C++ function name associated with the foreign call target address.
+ String functionName = DataBuilder.getVMFunctionNameForAddress(foreignCallTargetAddress);
+ if (functionName != null) {
+ // Use the known global AOT symbol associated with function name, if one exists
+ String aotSymbol = BinaryContainer.getAOTSymbolForVMFunctionName(functionName);
+ if (aotSymbol == null) {
+ throw new InternalError("no global symbol found for: " + functionName);
+ }
+ return aotSymbol;
+ }
+
+ // Is it a Graal stub we are calling?
+ if (callTarget.isCompiledStub()) {
+ assert call.direct : "Should always be a direct call to stubs";
+ return callTarget.getSymbol();
+ }
+
+ throw new InternalError("no symbol found for: " + callTarget);
+ }
+
+ private static RelocType getRelocType(HotSpotForeignCallLinkage callTarget) {
+ return callTarget.isCompiledStub() ? RelocType.STUB_CALL_DIRECT : RelocType.FOREIGN_CALL_INDIRECT_GOT;
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationSymbol.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationSymbol.java
new file mode 100644
index 000000000..22ec18437
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationSymbol.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+
+/**
+ * Native function call, symbol is to a VM method.
+ */
+final class ForeignCallSiteRelocationSymbol extends CallSiteRelocationSymbol {
+
+ ForeignCallSiteRelocationSymbol(CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) {
+ super(binaryContainer.createSymbol(0, Kind.NATIVE_FUNCTION, Binding.GLOBAL, 0, callSiteRelocation.targetSymbol));
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignGotCallSiteRelocationSymbol.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignGotCallSiteRelocationSymbol.java
new file mode 100644
index 000000000..a99aacf7b
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignGotCallSiteRelocationSymbol.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Symbol;
+
+import jdk.vm.ci.code.site.Call;
+
+final class ForeignGotCallSiteRelocationSymbol extends CallSiteRelocationSymbol {
+
+ ForeignGotCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation, DataBuilder dataBuilder) {
+ super(createPltSymbol(dataBuilder, mi, call, callSiteRelocation));
+ }
+
+ private static Symbol createPltSymbol(DataBuilder dataBuilder, CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation) {
+ BinaryContainer binaryContainer = dataBuilder.getBinaryContainer();
+ String vmSymbolName = callSiteRelocation.targetSymbol;
+
+ // Add relocation to GOT cell for call resolution jump.
+ String pltSymbolName = "plt." + vmSymbolName;
+ Symbol pltSymbol = binaryContainer.getSymbol(pltSymbolName);
+
+ if (pltSymbol == null) {
+ String gotSymbolName = "got." + vmSymbolName;
+ Symbol gotSymbol = binaryContainer.getGotSymbol(gotSymbolName);
+ assert gotSymbol != null : "undefined VM got symbol '" + gotSymbolName + "' for call at " + call.pcOffset + " in " + mi.getMethodInfo().getSymbolName();
+
+ // Generate PLT jump (do it only once).
+ final int pltStartOffset = binaryContainer.getCodeContainer().getByteStreamSize();
+ final int pltEndOffset = pltStartOffset + addPltJump(dataBuilder);
+
+ // Link GOT cell to PLT jump.
+ pltSymbol = createCodeContainerSymbol(binaryContainer, pltSymbolName, pltStartOffset);
+ addExternalPltToGotRelocation(binaryContainer, gotSymbol, pltEndOffset);
+ }
+
+ return pltSymbol;
+ }
+
+ private static int addPltJump(DataBuilder dataBuilder) {
+ ELFMacroAssembler masm = ELFMacroAssembler.getELFMacroAssembler(dataBuilder.getBackend().getTarget(), dataBuilder.getBackend().getRuntime().getOptions());
+ byte[] code = masm.getPLTJumpCode(); // It includes alignment nops.
+ int size = masm.currentEndOfInstruction();
+ dataBuilder.getBinaryContainer().appendCodeBytes(code, 0, code.length);
+ return size;
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java
new file mode 100644
index 000000000..032402462
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions;
+import org.graalvm.compiler.hotspot.word.MetaspacePointer;
+import org.graalvm.compiler.replacements.Snippets;
+import jdk.internal.vm.compiler.word.WordBase;
+
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.hotspot.HotSpotConstantPool;
+
+final class GraalFilters {
+ private List<ResolvedJavaType> specialClasses;
+ private List<ResolvedJavaType> specialArgumentAndReturnTypes;
+
+ private static Set<Class<?>> skipAnnotations = new HashSet<>();
+
+ static {
+ skipAnnotations.add(NodeIntrinsic.class);
+ skipAnnotations.add(Snippet.class);
+ skipAnnotations.add(MethodSubstitution.class);
+ }
+
+ boolean shouldCompileMethod(ResolvedJavaMethod method) {
+ // NodeIntrinsics cannot be compiled.
+ if (hasExcludedAnnotation(method)) {
+ return false;
+ }
+
+ ResolvedJavaType declaringClass = method.getDeclaringClass();
+ // Check for special magical types in the signature, like Word or MetaspacePointer. Those
+ // are definitely snippets.
+ List<ResolvedJavaType> signatureTypes = Arrays.asList(method.toParameterTypes()).stream().map(p -> p.resolve(declaringClass)).collect(Collectors.toList());
+ signatureTypes.add(method.getSignature().getReturnType(null).resolve(declaringClass));
+ if (signatureTypes.stream().flatMap(t -> specialArgumentAndReturnTypes.stream().filter(s -> s.isAssignableFrom(t))).findAny().isPresent()) {
+ return false;
+ }
+ return true;
+ }
+
+ private static boolean hasExcludedAnnotation(ResolvedJavaMethod method) {
+ for (Annotation annotation : method.getAnnotations()) {
+ if (skipAnnotations.contains(annotation.annotationType())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ boolean shouldCompileAnyMethodInClass(ResolvedJavaType klass) {
+ if (specialClasses.stream().filter(s -> s.isAssignableFrom(klass)).findAny().isPresent()) {
+ return false;
+ }
+ // Skip klass with Condy until Graal is fixed.
+ if (((HotSpotConstantPool) ((HotSpotResolvedObjectType) klass).getConstantPool()).hasDynamicConstant()) {
+ return false;
+ }
+ return true;
+ }
+
+ // Don't compile methods in classes and their subtypes that are in the list.
+ private static List<ResolvedJavaType> getSpecialClasses(MetaAccessProvider meta) {
+ // @formatter:off
+ return Arrays.asList(meta.lookupJavaType(Snippets.class),
+ meta.lookupJavaType(HotSpotClassSubstitutions.class),
+ meta.lookupJavaType(GraalDirectives.class),
+ meta.lookupJavaType(ClassSubstitution.class));
+ // @formatter:on
+ }
+
+ // Don't compile methods that have have the listed class or their subtypes in their signature.
+ private static List<ResolvedJavaType> getSpecialArgumentAndReturnTypes(MetaAccessProvider meta) {
+ // @formatter:off
+ return Arrays.asList(meta.lookupJavaType(WordBase.class),
+ meta.lookupJavaType(MetaspacePointer.class));
+ // @formatter:on
+ }
+
+ GraalFilters(MetaAccessProvider metaAccess) {
+ specialClasses = getSpecialClasses(metaAccess);
+ specialArgumentAndReturnTypes = getSpecialArgumentAndReturnTypes(metaAccess);
+ }
+
+ static boolean shouldIgnoreException(Throwable e) {
+ if (e instanceof GraalError) {
+ String m = e.getMessage();
+ if (m.contains("ArrayKlass::_component_mirror")) {
+ // When compiling Graal, ignore errors in JDK8 snippets.
+ return true;
+ }
+ }
+
+ if (e instanceof org.graalvm.compiler.java.BytecodeParser.BytecodeParserError) {
+ Throwable cause = e.getCause();
+ if (cause instanceof GraalError) {
+ String m = cause.getMessage();
+ // When compiling Graal suppress attempts to compile snippet fragments that bottom
+ // out with node intrinsics. These are unfortunately not explicitly marked, so we
+ // have to try to compile them and bail out if we think it's a snippet.
+ if (m.contains("@NodeIntrinsic method") && m.contains("must only be called from within a replacement")) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InfopointProcessor.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InfopointProcessor.java
new file mode 100644
index 000000000..f6974cc34
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InfopointProcessor.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Relocation;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+
+import jdk.vm.ci.code.BytecodePosition;
+import jdk.vm.ci.code.VirtualObject;
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.code.site.Infopoint;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.InvokeTarget;
+
+final class InfopointProcessor {
+
+ private final DataBuilder dataBuilder;
+
+ private final BinaryContainer binaryContainer;
+
+ InfopointProcessor(DataBuilder dataBuilder) {
+ this.dataBuilder = dataBuilder;
+ this.binaryContainer = dataBuilder.getBinaryContainer();
+ }
+
+ /**
+ * Parse an {@link Infopoint} generated by the compiler and create all needed binary section
+ * constructs.
+ *
+ * @param methodInfo compiled method info
+ * @param info info point being processed
+ */
+ void process(CompiledMethodInfo methodInfo, Infopoint info) {
+ switch (info.reason) {
+ case CALL:
+ // All calls in compiled code need a symbol and relocation entry.
+ processCallInfoPoint(methodInfo, (Call) info);
+ break;
+ case SAFEPOINT:
+ case IMPLICIT_EXCEPTION:
+ case METHOD_START:
+ case METHOD_END:
+ case BYTECODE_POSITION:
+ break;
+ default:
+ throw new InternalError("Unknown info point reason: " + info.reason);
+ }
+ if (info.debugInfo == null) {
+ return;
+ }
+ BytecodePosition bcp = info.debugInfo.getBytecodePosition();
+ if (bcp == null) {
+ return;
+ }
+ recordScopeKlasses(methodInfo, bcp, info.debugInfo.getVirtualObjectMapping());
+ }
+
+ private void recordScopeKlasses(CompiledMethodInfo methodInfo, BytecodePosition bcp, VirtualObject[] vos) {
+ BytecodePosition caller = bcp.getCaller();
+ if (caller != null) {
+ recordScopeKlasses(methodInfo, caller, vos);
+ }
+
+ HotSpotResolvedJavaMethod m = (HotSpotResolvedJavaMethod) bcp.getMethod();
+ HotSpotResolvedObjectType klass = m.getDeclaringClass();
+ methodInfo.addDependentKlassData(binaryContainer, klass);
+
+ if (vos == null) {
+ return;
+ }
+ for (VirtualObject vo : vos) {
+ HotSpotResolvedObjectType vk = (HotSpotResolvedObjectType) vo.getType();
+ methodInfo.addDependentKlassData(binaryContainer, vk);
+ }
+
+ }
+
+ /**
+ * Process Call info points in Graal generated compilation result. We want to create one of the
+ * following relocations: .text -> .hotspot.plt.linkage - Java method to Java method call .text
+ * -> .text - Java method / Graal stub to Graal stub call .text -> .plt - Java method / Graal
+ * stub to VM method call.
+ *
+ * @param methodInfo compiled method info
+ * @param call call
+ */
+ private void processCallInfoPoint(CompiledMethodInfo methodInfo, Call call) {
+ CallSiteRelocationInfo callSiteRelocation = getCallSiteRelocationInfo(call);
+ CallSiteRelocationSymbol callSiteRelocationSymbol = getCallSiteRelocationSymbol(methodInfo, call, callSiteRelocation);
+
+ Relocation relocation = new Relocation(methodInfo.getTextSectionOffset() + call.pcOffset, callSiteRelocation.type, call.size, binaryContainer.getCodeContainer(),
+ callSiteRelocationSymbol.symbol);
+ binaryContainer.addRelocation(relocation);
+ }
+
+ /**
+ * Get information about the call site. Name of the callee and relocation call type.
+ */
+ private static CallSiteRelocationInfo getCallSiteRelocationInfo(Call call) {
+ InvokeTarget callTarget = call.target;
+ if (callTarget instanceof HotSpotResolvedJavaMethod) {
+ return new JavaCallSiteRelocationInfo(call, (HotSpotResolvedJavaMethod) callTarget);
+ } else if (callTarget instanceof HotSpotForeignCallLinkage) {
+ return new ForeignCallSiteRelocationInfo(call, (HotSpotForeignCallLinkage) callTarget);
+ } else {
+ throw new InternalError("Unhandled call type found in infopoint: " + callTarget);
+ }
+ }
+
+ /**
+ * Return a relocation symbol for the given call site.
+ */
+ private CallSiteRelocationSymbol getCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation) {
+ switch (callSiteRelocation.type) {
+ case STUB_CALL_DIRECT:
+ return new StubDirectCallSiteRelocationSymbol(callSiteRelocation, binaryContainer);
+ case FOREIGN_CALL_INDIRECT_GOT:
+ return new ForeignGotCallSiteRelocationSymbol(mi, call, callSiteRelocation, dataBuilder);
+ default:
+ return new JavaCallSiteRelocationSymbol(mi, call, callSiteRelocation, binaryContainer);
+ }
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InstructionDecoder.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InstructionDecoder.java
new file mode 100644
index 000000000..6907cf30e
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InstructionDecoder.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.amd64.AMD64InstructionDecoder;
+import jdk.tools.jaotc.aarch64.AArch64InstructionDecoder;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.TargetDescription;
+
+public abstract class InstructionDecoder {
+
+ public static InstructionDecoder getInstructionDecoder(TargetDescription target) {
+ Architecture architecture = target.arch;
+ if (architecture instanceof AMD64) {
+ return new AMD64InstructionDecoder(target);
+ } else if (architecture instanceof AArch64) {
+ return new AArch64InstructionDecoder();
+ } else {
+ throw new InternalError("Unsupported architecture " + architecture);
+ }
+ }
+
+ public abstract void decodePosition(byte[] code, int pcOffset);
+
+ public abstract int currentEndOfInstruction();
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationInfo.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationInfo.java
new file mode 100644
index 000000000..aa79e75bd
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationInfo.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+
+/**
+ * This is a Java call site. Get the Java method name and correct call relocation type. All static
+ * Java calls should be direct. All virtual Java calls should be indirect.
+ */
+final class JavaCallSiteRelocationInfo extends CallSiteRelocationInfo {
+
+ JavaCallSiteRelocationInfo(Call call, HotSpotResolvedJavaMethod callTarget) {
+ super(JavaMethodInfo.uniqueMethodName(callTarget), call.direct ? RelocType.JAVA_CALL_DIRECT : RelocType.JAVA_CALL_INDIRECT);
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java
new file mode 100644
index 000000000..27cfb49fb
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import org.graalvm.compiler.hotspot.HotSpotMarkId;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Symbol;
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+
+/**
+ * Symbol for a regular Java call. This method also creates additional relocations for {@code .plt}
+ * to {@code .got} and {@code .got} to {@code .plt}.
+ */
+final class JavaCallSiteRelocationSymbol extends CallSiteRelocationSymbol {
+
+ private static final byte[] zeroSlot = new byte[8];
+ // -1 represents Universe::non_oop_word() value
+ private static final byte[] minusOneSlot;
+
+ static {
+ String archStr = System.getProperty("os.arch").toLowerCase();
+ if (archStr.equals("aarch64")) {
+ // AArch64 is a special case: it uses 48-bit addresses.
+ byte[] nonOopWord = {-1, -1, -1, -1, -1, -1, 0, 0};
+ minusOneSlot = nonOopWord;
+ } else {
+ byte[] nonOopWord = {-1, -1, -1, -1, -1, -1, -1, -1};
+ minusOneSlot = nonOopWord;
+ }
+ }
+
+ JavaCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) {
+ super(createPltEntrySymbol(binaryContainer, mi, call, callSiteRelocation));
+ StubInformation stub = getStub(mi, call);
+ addRelocations(mi, stub, binaryContainer, call, callSiteRelocation);
+ }
+
+ /**
+ * Returns a unique symbol name with the {@code suffix} appended.
+ */
+ private static String relocationSymbolName(String suffix, CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation) {
+ return "M" + mi.getCodeId() + "_" + call.pcOffset + "_" + callSiteRelocation.targetSymbol + "_" + suffix;
+ }
+
+ private static Symbol createPltEntrySymbol(BinaryContainer binaryContainer, CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation) {
+ String symbolName = relocationSymbolName("plt.entry", mi, call, callSiteRelocation);
+ StubInformation stub = getStub(mi, call);
+ return createCodeContainerSymbol(binaryContainer, symbolName, stub.getOffset());
+ }
+
+ private static StubInformation getStub(CompiledMethodInfo mi, Call call) {
+ HotSpotResolvedJavaMethod callTarget = (HotSpotResolvedJavaMethod) call.target;
+ String callTargetSymbol = JavaMethodInfo.uniqueMethodName(callTarget) + ".at." + call.pcOffset;
+ return mi.getStubFor(callTargetSymbol);
+ }
+
+ /**
+ * Add all the required relocations.
+ */
+ private static void addRelocations(CompiledMethodInfo mi, StubInformation stub, BinaryContainer binaryContainer, Call call, CallSiteRelocationInfo callSiteRelocation) {
+ final boolean isVirtualCall = CallInfo.isVirtualCall(mi, call);
+
+ final int gotStartOffset = binaryContainer.appendExtLinkageGotBytes(zeroSlot, 0, zeroSlot.length);
+ if (isVirtualCall) {
+ // Nothing.
+ } else {
+ // For c2i stub we need slot with -1 value.
+ binaryContainer.appendExtLinkageGotBytes(minusOneSlot, 0, minusOneSlot.length);
+ }
+
+ // Add relocation to GOT cell for call resolution jump.
+ // This GOT cell will be initialized during JVM startup with address
+ // of JVM runtime call resolution function.
+ String gotSymbolName = "got." + getResolveSymbolName(mi, call);
+ Symbol gotSymbol = binaryContainer.getGotSymbol(gotSymbolName);
+ addExternalPltToGotRelocation(binaryContainer, gotSymbol, stub.getResolveJumpOffset());
+
+ // Add relocation to resolve call jump instruction address for GOT cell.
+ // This GOT cell will be initialized with address of resolution jump instruction and
+ // will be updated with call destination address by JVM runtime call resolution code.
+ String pltJmpSymbolName = relocationSymbolName("plt.jmp", mi, call, callSiteRelocation);
+ addCodeContainerRelocation(binaryContainer, pltJmpSymbolName, stub.getResolveJumpStart(), gotStartOffset);
+
+ // Add relocation to GOT cell for dispatch jump.
+ // The dispatch jump loads destination address from this GOT cell.
+ String gotEntrySymbolName = relocationSymbolName("got.entry", mi, call, callSiteRelocation);
+ addExtLinkageGotContainerRelocation(binaryContainer, gotEntrySymbolName, gotStartOffset, stub.getDispatchJumpOffset());
+
+ // Virtual call needs initial -1 value for Klass pointer.
+ // Non virtual call needs initial 0 value for Method pointer to call c2i adapter.
+ byte[] slot = isVirtualCall ? minusOneSlot : zeroSlot;
+ final int gotMetaOffset = binaryContainer.appendExtLinkageGotBytes(slot, 0, slot.length);
+
+ // Add relocation to GOT cell for move instruction (Klass* for virtual, Method* otherwise).
+ String gotMoveSymbolName = relocationSymbolName("got.move", mi, call, callSiteRelocation);
+ addExtLinkageGotContainerRelocation(binaryContainer, gotMoveSymbolName, gotMetaOffset, stub.getMovOffset());
+
+ if (isVirtualCall) {
+ // Nothing.
+ } else {
+ // Add relocation to GOT cell for c2i adapter jump.
+ // The c2i jump instruction loads destination address from this GOT cell.
+ // This GOT cell is initialized with -1 and will be updated
+ // by JVM runtime call resolution code.
+ String gotC2ISymbolName = relocationSymbolName("got.c2i", mi, call, callSiteRelocation);
+ addExtLinkageGotContainerRelocation(binaryContainer, gotC2ISymbolName, gotStartOffset + 8, stub.getC2IJumpOffset());
+ }
+ }
+
+ /**
+ * Returns the name of the resolve method for this particular call.
+ */
+ private static String getResolveSymbolName(CompiledMethodInfo mi, Call call) {
+ String resolveSymbolName;
+ if (CallInfo.isStaticCall(call)) {
+ assert mi.hasMark(call, HotSpotMarkId.INVOKESTATIC);
+ resolveSymbolName = BinaryContainer.getResolveStaticEntrySymbolName();
+ } else if (CallInfo.isSpecialCall(call)) {
+ resolveSymbolName = BinaryContainer.getResolveOptVirtualEntrySymbolName();
+ } else if (CallInfo.isOptVirtualCall(mi, call)) {
+ resolveSymbolName = BinaryContainer.getResolveOptVirtualEntrySymbolName();
+ } else if (CallInfo.isVirtualCall(mi, call)) {
+ resolveSymbolName = BinaryContainer.getResolveVirtualEntrySymbolName();
+ } else {
+ throw new InternalError("Unknown call type in " + mi.asTag() + " @ " + call.pcOffset + " for call" + call.target);
+ }
+ return resolveSymbolName;
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaMethodInfo.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaMethodInfo.java
new file mode 100644
index 000000000..7bebfa3b9
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaMethodInfo.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import org.graalvm.compiler.code.CompilationResult;
+
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+interface JavaMethodInfo {
+
+ /**
+ * @return unique symbol name for this method.
+ */
+ String getSymbolName();
+
+ /**
+ * Name a java method with J.L.S. class name and signature.
+ *
+ * @return unique name for this method including class and signature
+ */
+ String getNameAndSignature();
+
+ HotSpotCompiledCode compiledCode(CompilationResult result);
+
+ /**
+ * Name a java method with class and signature to make it unique.
+ *
+ * @param method to generate unique identifier for
+ * @return Unique name for this method including class and signature
+ **/
+ static String uniqueMethodName(ResolvedJavaMethod method) {
+ String className = method.getDeclaringClass().toClassName();
+ String name = className + "." + method.getName() + method.getSignature().toMethodDescriptor();
+ return name;
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Linker.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Linker.java
new file mode 100644
index 000000000..92ac33e73
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Linker.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.stream.Stream;
+
+final class Linker {
+
+ private final Options options;
+ private String objectFileName;
+ private String libraryFileName;
+ private String linkerCmd;
+
+ String objFile() {
+ return objectFileName;
+ }
+
+ String libFile() {
+ return libraryFileName;
+ }
+
+ private static Stream<String> getLines(InputStream stream) {
+ return new BufferedReader(new InputStreamReader(stream)).lines();
+ }
+
+ private static String getString(InputStream stream) {
+ Stream<String> lines = getLines(stream);
+ StringBuilder sb = new StringBuilder();
+ lines.iterator().forEachRemaining(e -> sb.append(e));
+ return sb.toString();
+ }
+
+ Linker(Main main) throws Exception {
+ this.options = main.options;
+ String name = options.outputName;
+ objectFileName = name;
+ libraryFileName = name;
+
+ if (options.linkerpath != null && !(new File(options.linkerpath).exists())) {
+ throw new InternalError("Invalid linker path: " + options.linkerpath);
+ }
+ String linkerPath;
+ String linkerCheck;
+
+ switch (options.osName) {
+ case "Linux":
+ if (name.endsWith(".so")) {
+ objectFileName = name.substring(0, name.length() - ".so".length());
+ }
+ objectFileName = objectFileName + ".o";
+ linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
+ linkerCmd = linkerPath + " -shared -z noexecstack -o " + libraryFileName + " " + objectFileName;
+ linkerCheck = linkerPath + " -v";
+ break;
+ case "Mac OS X":
+ if (name.endsWith(".dylib")) {
+ objectFileName = name.substring(0, name.length() - ".dylib".length());
+ }
+ objectFileName = objectFileName + ".o";
+ linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
+ linkerCmd = linkerPath + " -dylib -o " + libraryFileName + " " + objectFileName;
+ linkerCheck = linkerPath + " -v";
+ break;
+ default:
+ if (options.osName.startsWith("Windows")) {
+ if (name.endsWith(".dll")) {
+ objectFileName = name.substring(0, name.length() - ".dll".length());
+ }
+ objectFileName = objectFileName + ".obj";
+ linkerPath = (options.linkerpath != null) ? options.linkerpath : getWindowsLinkPath(main);
+ if (linkerPath == null) {
+ throw new InternalError("Can't locate Microsoft Visual Studio amd64 link.exe");
+ }
+ linkerCmd = linkerPath + " /DLL /OPT:NOREF /NOLOGO /NOENTRY" + " /OUT:" + libraryFileName + " " + objectFileName;
+ linkerCheck = null; // link.exe presence is verified already
+ break;
+ } else {
+ throw new InternalError("Unsupported platform: " + options.osName);
+ }
+ }
+
+ // Check linker presence on platforms by printing its version
+ if (linkerCheck != null) {
+ Process p = Runtime.getRuntime().exec(linkerCheck);
+ final int exitCode = p.waitFor();
+ if (exitCode != 0) {
+ throw new InternalError(getString(p.getErrorStream()));
+ }
+ }
+
+ main.printer.printlnVerbose("Found linker: " + linkerPath);
+ }
+
+ void link() throws Exception {
+ Process p = Runtime.getRuntime().exec(linkerCmd);
+ final int exitCode = p.waitFor();
+ if (exitCode != 0) {
+ String errorMessage = getString(p.getErrorStream());
+ if (errorMessage.isEmpty()) {
+ errorMessage = getString(p.getInputStream());
+ }
+ throw new InternalError(errorMessage);
+ }
+ File objFile = new File(objectFileName);
+ boolean keepObjFile = Boolean.parseBoolean(System.getProperty("aot.keep.objFile", "false"));
+ if (objFile.exists() && !keepObjFile) {
+ if (!objFile.delete()) {
+ throw new InternalError("Failed to delete " + objectFileName + " file");
+ }
+ }
+ // Make non-executable for all.
+ File libFile = new File(libraryFileName);
+ if (libFile.exists() && !options.osName.startsWith("Windows")) {
+ if (!libFile.setExecutable(false, false)) {
+ throw new InternalError("Failed to change attribute for " + libraryFileName + " file");
+ }
+ }
+
+ }
+
+ /**
+ * Search for Visual Studio link.exe Search Order is: VS2017+, VS2013, VS2015, VS2012.
+ */
+ private static String getWindowsLinkPath(Main main) throws Exception {
+ try {
+ Path vc141NewerLinker = getVC141AndNewerLinker();
+ if (vc141NewerLinker != null) {
+ return vc141NewerLinker.toString();
+ }
+ } catch (Exception e) {
+ main.printer.printlnVerbose("Could not find VC14 or newer version of linker: " + e.getMessage());
+ if (main.options.debug) {
+ e.printStackTrace();
+ }
+ }
+
+ String link = "\\VC\\bin\\amd64\\link.exe";
+
+ /**
+ * First try searching the paths pointed to by the VS environment variables.
+ */
+ for (VSVERSIONS vs : VSVERSIONS.values()) {
+ String vspath = System.getenv(vs.getEnvVariable());
+ if (vspath != null) {
+ File commonTools = new File(vspath);
+ File vsRoot = commonTools.getParentFile().getParentFile();
+ File linkPath = new File(vsRoot, link);
+ if (linkPath.exists()) {
+ return linkPath.getPath();
+ }
+ }
+ }
+
+ /**
+ * If we didn't find via the VS environment variables, try the well known paths
+ */
+ for (VSVERSIONS vs : VSVERSIONS.values()) {
+ String wkp = vs.getWellKnownPath();
+ if (new File(wkp).exists()) {
+ return wkp;
+ }
+ }
+
+ return null;
+ }
+
+ private static Path getVC141AndNewerLinker() throws Exception {
+ String programFilesX86 = System.getenv("ProgramFiles(x86)");
+ if (programFilesX86 == null) {
+ throw new IllegalStateException("Could not read the ProgramFiles(x86) environment variable");
+ }
+ String vswherePath = programFilesX86 + "\\Microsoft Visual Studio\\Installer\\vswhere.exe";
+ Path vswhere = Paths.get(vswherePath);
+ if (!Files.exists(vswhere)) {
+ throw new IllegalStateException("Could not find " + vswherePath);
+ }
+
+ ProcessBuilder processBuilder = new ProcessBuilder(vswhere.toString(), "-requires",
+ "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", "-property", "installationPath", "-latest");
+ processBuilder.redirectOutput(ProcessBuilder.Redirect.PIPE);
+ processBuilder.redirectError(ProcessBuilder.Redirect.PIPE);
+ Process process = processBuilder.start();
+ final int exitCode = process.waitFor();
+ if (exitCode != 0) {
+ String errorMessage = getString(process.getErrorStream());
+ if (errorMessage.isEmpty()) {
+ errorMessage = getString(process.getInputStream());
+ }
+ throw new IllegalStateException("vswhere error: " + errorMessage);
+ }
+
+ String installationPath = getLines(process.getInputStream()).findFirst().orElseThrow(() -> new IllegalStateException("Unexpected empty output from vswhere"));
+ Path vcToolsVersionFilePath = Paths.get(installationPath, "VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt");
+ List<String> vcToolsVersionFileLines = Files.readAllLines(vcToolsVersionFilePath);
+ if (vcToolsVersionFileLines.isEmpty()) {
+ throw new IllegalStateException(vcToolsVersionFilePath.toString() + " is empty");
+ }
+ String vcToolsVersion = vcToolsVersionFileLines.get(0);
+ Path linkPath = Paths.get(installationPath, "VC\\Tools\\MSVC", vcToolsVersion, "bin\\Hostx64\\x64\\link.exe");
+ if (!Files.exists(linkPath)) {
+ throw new IllegalStateException("Linker at path " + linkPath.toString() + " does not exist");
+ }
+
+ return linkPath;
+ }
+
+ // @formatter:off (workaround for Eclipse formatting bug)
+ enum VSVERSIONS {
+ VS2013("VS120COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64\\link.exe"),
+ VS2015("VS140COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\bin\\amd64\\link.exe"),
+ VS2012("VS110COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC\\bin\\amd64\\link.exe");
+
+ private final String envvariable;
+ private final String wkp;
+
+ VSVERSIONS(String envvariable, String wellknownpath) {
+ this.envvariable = envvariable;
+ this.wkp = wellknownpath;
+ }
+
+ String getEnvVariable() {
+ return envvariable;
+ }
+
+ String getWellKnownPath() {
+ return wkp;
+ }
+ }
+ // @formatter:on
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java
new file mode 100644
index 000000000..3b6d6f4d5
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+public class LoadedClass {
+ private final String name;
+ private final Class<?> clz;
+
+ public LoadedClass(String name, Class<?> clz) {
+ this.name = name;
+ this.clz = clz;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Class<?> getLoadedClass() {
+ return clz;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof LoadedClass)) {
+ return false;
+ }
+ LoadedClass that = (LoadedClass) o;
+
+ if (name != null ? !name.equals(that.name) : that.name != null) {
+ return false;
+ }
+ return clz != null ? clz.equals(that.clz) : that.clz == null;
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = name != null ? name.hashCode() : 0;
+ result = 31 * result + (clz != null ? clz.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LogPrinter.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LogPrinter.java
new file mode 100644
index 000000000..fc1ad5e9e
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LogPrinter.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryUsage;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.MessageFormat;
+import java.util.Date;
+
+import jdk.tools.jaotc.binformat.ByteContainer;
+import jdk.tools.jaotc.binformat.BinaryContainer;
+
+final class LogPrinter {
+
+ private static FileWriter logFile = null;
+ private final Options options;
+ private final PrintWriter log;
+
+ LogPrinter(Main main, PrintWriter log) {
+ this.options = main.options;
+ this.log = log;
+ }
+
+ void printInfo(String message) {
+ if (options.info) {
+ log.print(message);
+ log.flush();
+ }
+ }
+
+ void printlnInfo(String message) {
+ if (options.info) {
+ log.println(message);
+ log.flush();
+ }
+ }
+
+ void printVerbose(String message) {
+ if (options.verbose) {
+ log.print(message);
+ log.flush();
+ }
+ }
+
+ void printlnVerbose(String message) {
+ if (options.verbose) {
+ log.println(message);
+ log.flush();
+ }
+ }
+
+ void printDebug(String message) {
+ if (options.debug) {
+ log.print(message);
+ log.flush();
+ }
+ }
+
+ void printlnDebug(String message) {
+ if (options.debug) {
+ log.println(message);
+ log.flush();
+ }
+ }
+
+ void printError(String message) {
+ log.println("Error: " + message);
+ log.flush();
+ }
+
+ void reportError(Throwable e) {
+ log.println("Error: " + e.getMessage());
+ if (options.info) {
+ e.printStackTrace(log);
+ }
+ log.flush();
+ }
+
+ void reportError(String key, Object... args) {
+ printError(MessageFormat.format(key, args));
+ }
+
+ private static String humanReadableByteCount(long bytes) {
+ int unit = 1024;
+
+ if (bytes < unit) {
+ return bytes + " B";
+ }
+
+ int exp = (int) (Math.log(bytes) / Math.log(unit));
+ char pre = "KMGTPE".charAt(exp - 1);
+ return String.format("%.1f %cB", bytes / Math.pow(unit, exp), pre);
+ }
+
+ void printMemoryUsage() {
+ if (options.verbose) {
+ MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
+ float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted();
+ log.format(" [used: %-7s, comm: %-7s, freeRatio ~= %.1f%%]",
+ humanReadableByteCount(memusage.getUsed()),
+ humanReadableByteCount(memusage.getCommitted()),
+ freeratio * 100);
+ }
+ }
+
+ private void printContainerInfo(ByteContainer container) {
+ printlnVerbose(container.getContainerName() + ": " + container.getByteStreamSize() + " bytes");
+ }
+
+ void containersInfo(BinaryContainer binaryContainer) {
+ printContainerInfo(binaryContainer.getHeaderContainer().getContainer());
+ printContainerInfo(binaryContainer.getConfigContainer());
+ printContainerInfo(binaryContainer.getKlassesOffsetsContainer());
+ printContainerInfo(binaryContainer.getMethodsOffsetsContainer());
+ printContainerInfo(binaryContainer.getKlassesDependenciesContainer());
+ printContainerInfo(binaryContainer.getStubsOffsetsContainer());
+ printContainerInfo(binaryContainer.getMethodMetadataContainer());
+ printContainerInfo(binaryContainer.getCodeContainer());
+ printContainerInfo(binaryContainer.getCodeSegmentsContainer());
+ printContainerInfo(binaryContainer.getConstantDataContainer());
+ printContainerInfo(binaryContainer.getKlassesGotContainer());
+ printContainerInfo(binaryContainer.getCountersGotContainer());
+ printContainerInfo(binaryContainer.getMetadataGotContainer());
+ printContainerInfo(binaryContainer.getMethodStateContainer());
+ printContainerInfo(binaryContainer.getOopGotContainer());
+ printContainerInfo(binaryContainer.getMetaspaceNamesContainer());
+ }
+
+ static void openLog() {
+ int v = Integer.getInteger("jdk.tools.jaotc.logCompilation", 0);
+ if (v == 0) {
+ logFile = null;
+ return;
+ }
+ // Create log file in current directory
+ String fileName = "aot_compilation" + new Date().getTime() + ".log";
+ Path logFilePath = Paths.get("./", fileName);
+ String logFileName = logFilePath.toString();
+ try {
+ // Create file to which we do not append
+ logFile = new FileWriter(logFileName, false);
+ } catch (IOException e) {
+ System.out.println("Unable to open logfile :" + logFileName + "\nNo logs will be created");
+ logFile = null;
+ }
+ }
+
+ static void writeLog(String str) {
+ if (logFile != null) {
+ try {
+ logFile.write(str + "\n");
+ logFile.flush();
+ } catch (IOException e) {
+ // Print to console
+ System.out.println(str + "\n");
+ }
+ }
+ }
+
+ static void closeLog() {
+ if (logFile != null) {
+ try {
+ logFile.close();
+ } catch (IOException e) {
+ // Do nothing
+ }
+ }
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java
new file mode 100644
index 000000000..bb9bc1667
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.stream.Stream;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
+import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.debug.DebugContext.Activation;
+import org.graalvm.compiler.debug.DebugContext.Builder;
+import org.graalvm.compiler.hotspot.CompilerConfigurationFactory;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory;
+import org.graalvm.compiler.hotspot.HotSpotGraalOptionValues;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntime;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntime.HotSpotGC;
+import org.graalvm.compiler.hotspot.HotSpotHostBackend;
+import org.graalvm.compiler.hotspot.HotSpotMarkId;
+import org.graalvm.compiler.hotspot.meta.HotSpotInvokeDynamicPlugin;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+import jdk.tools.jaotc.Options.Option;
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.runtime.JVMCI;
+
+public final class Main {
+
+ final Options options = new Options();
+ private PrintWriter log;
+ LogPrinter printer;
+ GraalFilters filters;
+
+ private static final int EXIT_OK = 0; // No errors.
+ private static final int EXIT_CMDERR = 2; // Bad command-line arguments and/or switches.
+ private static final int EXIT_ABNORMAL = 4; // Terminated abnormally.
+
+ private static final String PROGNAME = "jaotc";
+
+ private static final String JVM_VERSION = System.getProperty("java.runtime.version");
+
+ public static void main(String[] args) throws Exception {
+ Main t = new Main();
+ final int exitCode = t.run(parse(args));
+ System.exit(exitCode);
+ }
+
+ /**
+ * Expands '@file' in command line arguments by replacing '@file' with the content of 'file'
+ * parsed by StringTokenizer. '@' character can be quoted as '@@'.
+ */
+ private static String[] parse(String[] args) throws IOException {
+ List<String> result = new ArrayList<>();
+ for (String arg : args) {
+ if (arg.length() > 1 && arg.charAt(0) == '@') {
+ String v = arg.substring(1);
+ if (v.charAt(0) == '@') {
+ result.add(v);
+ } else {
+ try (Stream<String> file = Files.lines(Paths.get(v))) {
+ file.map(StringTokenizer::new).map(Collections::list).flatMap(l -> l.stream().map(o -> (String) o)).forEachOrdered(result::add);
+ }
+ }
+ } else {
+ result.add(arg);
+ }
+ }
+ return result.toArray(String[]::new);
+ }
+
+ private int run(String[] args) {
+ log = new PrintWriter(System.out);
+ printer = new LogPrinter(this, log);
+
+ try {
+ Options.handleOptions(this, args);
+ if (options.help) {
+ showHelp();
+ return EXIT_OK;
+ }
+ if (options.version) {
+ showVersion();
+ return EXIT_OK;
+ }
+
+ printer.printlnInfo("Compiling " + options.outputName + "...");
+ final long start = System.currentTimeMillis();
+ if (!run()) {
+ return EXIT_ABNORMAL;
+ }
+ final long end = System.currentTimeMillis();
+ printer.printlnInfo("Total time: " + (end - start) + " ms");
+
+ return EXIT_OK;
+ } catch (Options.BadArgs e) {
+ printer.reportError(e.key, e.args);
+ if (e.showUsage) {
+ showUsage();
+ }
+ return EXIT_CMDERR;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return EXIT_ABNORMAL;
+ } finally {
+ log.flush();
+ }
+ }
+
+ @SuppressWarnings("try")
+ private boolean run() throws Exception {
+ LogPrinter.openLog();
+
+ try {
+
+ final Linker linker = new Linker(this);
+ final String objectFileName = linker.objFile();
+ final Collector collector = new Collector(this);
+ Set<Class<?>> classesToCompile;
+
+ try (Timer t = new Timer(this, "")) {
+ classesToCompile = collector.collectClassesToCompile();
+ printer.printInfo(classesToCompile.size() + " classes found");
+ }
+
+ OptionValues graalOptions = HotSpotGraalOptionValues.defaultOptions();
+ // Setting -Dgraal.TieredAOT overrides --compile-for-tiered
+ if (!TieredAOT.hasBeenSet(graalOptions)) {
+ graalOptions = new OptionValues(graalOptions, TieredAOT, options.tiered);
+ }
+ graalOptions = new OptionValues(graalOptions, GeneratePIC, true, ImmutableCode, true);
+ GraalJVMCICompiler graalCompiler = HotSpotGraalCompilerFactory.createCompiler("JAOTC", JVMCI.getRuntime(), graalOptions, CompilerConfigurationFactory.selectFactory(null, graalOptions));
+ HotSpotGraalRuntime runtime = (HotSpotGraalRuntime) graalCompiler.getGraalRuntime();
+ GraalHotSpotVMConfig graalHotSpotVMConfig = runtime.getVMConfig();
+
+ if (graalHotSpotVMConfig.verifyOops) {
+ if (!HotSpotMarkId.VERIFY_OOPS.isAvailable() || !HotSpotMarkId.VERIFY_OOP_COUNT_ADDRESS.isAvailable()) {
+ System.err.println("Running jaotc with -XX:+VerifyOops is not supported by this JDK");
+ return false;
+ }
+ }
+
+ HotSpotHostBackend backend = (HotSpotHostBackend) runtime.getCapability(RuntimeProvider.class).getHostBackend();
+ MetaAccessProvider metaAccess = backend.getProviders().getMetaAccess();
+ filters = new GraalFilters(metaAccess);
+
+ List<AOTCompiledClass> classes;
+
+ try (Timer t = new Timer(this, "")) {
+ classes = collector.collectMethodsToCompile(classesToCompile, metaAccess);
+ }
+
+ // Free memory!
+ try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
+ printer.printMemoryUsage();
+ classesToCompile = null;
+ System.gc();
+ }
+
+ AOTDynamicTypeStore dynoStore = new AOTDynamicTypeStore();
+ AOTCompiledClass.setDynamicTypeStore(dynoStore);
+
+ // AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend, new
+ // HotSpotInvokeDynamicPlugin(dynoStore));
+ // Temporary workaround until JDK-8223533 is fixed.
+ // Disable invokedynamic support.
+ var indyPlugin = new HotSpotInvokeDynamicPlugin(dynoStore) {
+ @Override
+ public boolean supportsDynamicInvoke(GraphBuilderContext builder, int index, int opcode) {
+ return false;
+ }
+ };
+
+ AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend, indyPlugin);
+ SnippetReflectionProvider snippetReflection = aotBackend.getProviders().getSnippetReflection();
+ AOTCompiler compiler = new AOTCompiler(this, graalOptions, aotBackend, options.threads);
+ classes = compiler.compileClasses(classes);
+
+ PhaseSuite<HighTierContext> graphBuilderSuite = aotBackend.getGraphBuilderSuite();
+ ListIterator<BasePhase<? super HighTierContext>> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class);
+ GraphBuilderConfiguration graphBuilderConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig();
+
+ // Free memory!
+ try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
+ printer.printMemoryUsage();
+ aotBackend = null;
+ compiler = null;
+ System.gc();
+ }
+
+ HotSpotGC graalGC = runtime.getGarbageCollector();
+ // Prior to JDK 14, the Graal HotSpotGC enum order matched the JDK CollectedHeap enum
+ // order, so using the ordinal value worked fine. In JDK 14, CMS was removed on the
+ // JDK side, so we need a symbolic lookup of the JDK value.
+ int def = graalGC.ordinal() + 1;
+ // The GC names are spelled the same in both enums, so no clever remapping is needed
+ // here.
+ String name = "CollectedHeap::" + graalGC.name();
+ int gc = graalHotSpotVMConfig.getConstant(name, Integer.class, def, true);
+
+ BinaryContainer binaryContainer = new BinaryContainer(graalOptions, graalHotSpotVMConfig, graphBuilderConfig, gc, JVM_VERSION);
+ DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer);
+
+ try (DebugContext debug = new Builder(graalOptions, new GraalDebugHandlersFactory(snippetReflection)).build(); Activation a = debug.activate()) {
+ dataBuilder.prepareData(debug);
+ }
+
+ // Print information about section sizes
+ printer.containersInfo(binaryContainer);
+
+ // Free memory!
+ try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
+ printer.printMemoryUsage();
+ backend = null;
+ for (AOTCompiledClass aotCompClass : classes) {
+ aotCompClass.clear();
+ }
+ classes.clear();
+ classes = null;
+ dataBuilder = null;
+ binaryContainer.freeMemory();
+ System.gc();
+ }
+
+ try (Timer t = new Timer(this, "Creating binary: " + objectFileName)) {
+ binaryContainer.createBinary(objectFileName);
+ }
+
+ // Free memory!
+ try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
+ printer.printMemoryUsage();
+ binaryContainer = null;
+ System.gc();
+ }
+
+ try (Timer t = new Timer(this, "Creating shared library: " + linker.libFile())) {
+ linker.link();
+ }
+
+ printer.printVerbose("Final memory ");
+ printer.printMemoryUsage();
+ printer.printlnVerbose("");
+
+ } finally {
+ LogPrinter.closeLog();
+ }
+ return true;
+ }
+
+ void handleError(ResolvedJavaMethod resolvedMethod, Throwable e, String message) {
+ String methodName = JavaMethodInfo.uniqueMethodName(resolvedMethod);
+
+ if (options.debug) {
+ printer.printError("Failed compilation: " + methodName + ": " + e);
+ }
+
+ // Ignore some exceptions when meta-compiling Graal.
+ if (GraalFilters.shouldIgnoreException(e)) {
+ return;
+ }
+
+ LogPrinter.writeLog("Failed compilation of method " + methodName + message);
+
+ if (!options.debug) {
+ printer.printError("Failed compilation: " + methodName + ": " + e);
+ }
+
+ if (options.verbose) {
+ e.printStackTrace(log);
+ }
+
+ if (options.exitOnError) {
+ System.exit(1);
+ }
+ }
+
+ void warning(String key, Object... args) {
+ log.println("Warning: " + MessageFormat.format(key, args));
+ log.flush();
+ }
+
+ private void showUsage() {
+ log.println("Usage: " + PROGNAME + " <options> list");
+ log.println("use --help for a list of possible options");
+ log.flush();
+ }
+
+ private void showHelp() {
+ log.println("Usage: " + PROGNAME + " <options> list");
+ log.println();
+ log.println(" list A : separated list of class names, modules, jar files");
+ log.println(" or directories which contain class files.");
+ log.println();
+ log.println("where options include:");
+ for (Option o : Options.recognizedOptions) {
+ String name = o.aliases[0].substring(1); // there must always be at least one name
+ name = name.charAt(0) == '-' ? name.substring(1) : name;
+ if (o.isHidden() || name.equals("h")) {
+ continue;
+ }
+ log.println(o.help);
+ }
+ log.flush();
+ }
+
+ private void showVersion() {
+ log.println(PROGNAME + " " + JVM_VERSION);
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java
new file mode 100644
index 000000000..69c584d1c
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.hotspot.HotSpotMarkId;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Relocation;
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+import jdk.tools.jaotc.binformat.Symbol;
+import jdk.vm.ci.code.site.Mark;
+
+final class MarkProcessor {
+
+ private final BinaryContainer binaryContainer;
+
+ MarkProcessor(DataBuilder dataBuilder) {
+ binaryContainer = dataBuilder.getBinaryContainer();
+ }
+
+ /**
+ * Parse a {@link Mark} generated by the compiler and create all needed binary section
+ * constructs.
+ *
+ * @param methodInfo compiled method info
+ * @param mark mark being processed
+ */
+ @SuppressWarnings("fallthrough")
+ void process(CompiledMethodInfo methodInfo, CompilationResult.CodeMark mark) {
+ HotSpotMarkId markId = (HotSpotMarkId) mark.id;
+ switch (markId) {
+ case EXCEPTION_HANDLER_ENTRY:
+ case DEOPT_HANDLER_ENTRY:
+ case DEOPT_MH_HANDLER_ENTRY:
+ break;
+ case POLL_FAR:
+ case POLL_RETURN_FAR:
+ if (binaryContainer.getThreadLocalHandshakes()) {
+ // skip relocation
+ break;
+ }
+ // fallthrough
+ case CARD_TABLE_ADDRESS:
+ case NARROW_KLASS_BASE_ADDRESS:
+ case NARROW_OOP_BASE_ADDRESS:
+ case CRC_TABLE_ADDRESS:
+ case LOG_OF_HEAP_REGION_GRAIN_BYTES:
+ case VERIFY_OOPS:
+ case VERIFY_OOP_BITS:
+ case VERIFY_OOP_MASK:
+ case VERIFY_OOP_COUNT_ADDRESS:
+ String vmSymbolName;
+ switch (markId) {
+ case POLL_FAR:
+ case POLL_RETURN_FAR:
+ vmSymbolName = BinaryContainer.getPollingPageSymbolName();
+ break;
+ case CARD_TABLE_ADDRESS:
+ vmSymbolName = BinaryContainer.getCardTableAddressSymbolName();
+ break;
+ case NARROW_KLASS_BASE_ADDRESS:
+ vmSymbolName = BinaryContainer.getNarrowKlassBaseAddressSymbolName();
+ break;
+ case NARROW_OOP_BASE_ADDRESS:
+ vmSymbolName = BinaryContainer.getNarrowOopBaseAddressSymbolName();
+ break;
+ case CRC_TABLE_ADDRESS:
+ vmSymbolName = BinaryContainer.getCrcTableAddressSymbolName();
+ break;
+ case LOG_OF_HEAP_REGION_GRAIN_BYTES:
+ vmSymbolName = BinaryContainer.getLogOfHeapRegionGrainBytesSymbolName();
+ break;
+ case VERIFY_OOPS:
+ vmSymbolName = BinaryContainer.getVerifyOopsSymbolName();
+ break;
+ case VERIFY_OOP_COUNT_ADDRESS:
+ vmSymbolName = BinaryContainer.getVerifyOopCountAddressSymbolName();
+ break;
+ case VERIFY_OOP_BITS:
+ vmSymbolName = BinaryContainer.getVerifyOopBitsSymbolName();
+ break;
+ case VERIFY_OOP_MASK:
+ vmSymbolName = BinaryContainer.getVerifyOopMaskSymbolName();
+ break;
+ default:
+ throw new InternalError("Unhandled mark: " + mark);
+ }
+ String s = "got." + vmSymbolName;
+ Symbol gotSymbol = binaryContainer.getGotSymbol(s);
+ assert gotSymbol != null : " Processing Mark: Encountered undefined got symbol for " + mark;
+ final int textBaseOffset = methodInfo.getTextSectionOffset();
+ final int textOffset = textBaseOffset + mark.pcOffset;
+ Relocation reloc = new Relocation(textOffset, RelocType.EXTERNAL_PLT_TO_GOT, 8, binaryContainer.getCodeContainer(), gotSymbol);
+ binaryContainer.addRelocation(reloc);
+ break;
+ case VERIFIED_ENTRY:
+ case UNVERIFIED_ENTRY:
+ case OSR_ENTRY:
+ case FRAME_COMPLETE:
+ case INVOKEINTERFACE:
+ case INVOKEVIRTUAL:
+ case INVOKESTATIC:
+ case INVOKESPECIAL:
+ case INLINE_INVOKE:
+ case POLL_NEAR:
+ case POLL_RETURN_NEAR:
+ // Nothing to do.
+ break;
+ default:
+ throw new InternalError("Unexpected mark found: " + mark);
+ }
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java
new file mode 100644
index 000000000..817f6a2e2
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import static jdk.tools.jaotc.AOTCompiledClass.getType;
+import static jdk.tools.jaotc.AOTCompiledClass.metadataName;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.HotSpotGraalServices;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.ByteContainer;
+import jdk.tools.jaotc.binformat.GotSymbol;
+import jdk.tools.jaotc.utils.NativeOrderOutputStream;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.site.DataPatch;
+import jdk.vm.ci.code.site.Infopoint;
+import jdk.vm.ci.code.site.Mark;
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+import jdk.vm.ci.hotspot.HotSpotMetaData;
+
+final class MetadataBuilder {
+
+ private final DataBuilder dataBuilder;
+
+ private final BinaryContainer binaryContainer;
+
+ MetadataBuilder(DataBuilder dataBuilder) {
+ this.dataBuilder = dataBuilder;
+ this.binaryContainer = dataBuilder.getBinaryContainer();
+ }
+
+ /**
+ * Process compiled methods and create method metadata.
+ */
+ void processMetadata(List<AOTCompiledClass> classes, AOTCompiledClass stubCompiledCode) {
+ for (AOTCompiledClass c : classes) {
+ processMetadataClass(c);
+ }
+ processMetadataClass(stubCompiledCode);
+ }
+
+ private void processMetadataClass(AOTCompiledClass c) {
+ processInfopointsAndMarks(c);
+ createMethodMetadata(c);
+ }
+
+ /**
+ * Add metadata for each of the compiled methods in {@code compiledClass} to read-only section
+ * of {@code binaryContainer}.
+ *
+ * @param compiledClass AOT Graal compilation result
+ */
+ private void createMethodMetadata(AOTCompiledClass compiledClass) {
+ HotSpotGraalRuntimeProvider runtime = dataBuilder.getBackend().getRuntime();
+ ByteContainer methodMetadataContainer = binaryContainer.getMethodMetadataContainer();
+
+ // For each of the compiled java methods, create records holding information about them.
+ for (CompiledMethodInfo methodInfo : compiledClass.getCompiledMethods()) {
+ // Get the current offset in the methodmetadata container.
+ final int startOffset = methodMetadataContainer.getByteStreamSize();
+ assert startOffset % 8 == 0 : "Must be aligned on 8";
+
+ methodInfo.setMetadataOffset(startOffset);
+
+ HotSpotCompiledCode compiledMethod = methodInfo.compiledCode();
+ // pc and scope description
+ HotSpotMetaData metaData = new HotSpotMetaData(runtime.getTarget(), compiledMethod);
+
+ byte[] pcDesc = metaData.pcDescBytes();
+ byte[] scopeDesc = metaData.scopesDescBytes();
+ byte[] relocationInfo = metaData.relocBytes();
+ byte[] oopMapInfo = metaData.oopMaps();
+ // this may be null as the field does not exist before JDK 13
+ byte[] implicitExceptionBytes = HotSpotGraalServices.getImplicitExceptionBytes(metaData);
+ byte[] exceptionBytes = metaData.exceptionBytes();
+
+ // create a global symbol at this position for this method
+ NativeOrderOutputStream metadataStream = new NativeOrderOutputStream();
+
+ // get the code size
+ int codeSize = methodInfo.getCodeSize();
+
+ // get code offsets
+ CodeOffsets co = CodeOffsets.buildFrom(methodInfo.getCompilationResult().getMarks());
+ int unverifiedEntry = co.entry();
+ int verifiedEntry = co.verifiedEntry();
+ int exceptionHandler = co.exceptionHandler();
+ int deoptHandler = co.deoptHandler();
+ int deoptMHHandler = co.deoptMHHandler();
+ int frameSize = methodInfo.getCompilationResult().getTotalFrameSize();
+ StackSlot deoptRescueSlot = methodInfo.getCompilationResult().getCustomStackArea();
+ int origPcOffset = deoptRescueSlot != null ? deoptRescueSlot.getOffset(frameSize) : -1;
+
+ // get stubs offset
+ int stubsOffset = methodInfo.getStubsOffset();
+
+ int offset = addMetadataEntries(binaryContainer, metaData, methodInfo);
+ methodInfo.setMetadataGotOffset(offset);
+ methodInfo.setMetadataGotSize(metaData.metadataEntries().length);
+ int unsafeAccess = methodInfo.getCompilationResult().hasUnsafeAccess() ? 1 : 0;
+ try {
+ // calculate total size of the container
+ NativeOrderOutputStream.PatchableInt totalSize = metadataStream.patchableInt();
+
+ // @formatter:off
+ metadataStream.putInt(codeSize).
+ putInt(unverifiedEntry).
+ putInt(verifiedEntry).
+ putInt(exceptionHandler).
+ putInt(deoptHandler).
+ putInt(deoptMHHandler).
+ putInt(stubsOffset).
+ putInt(frameSize).
+ putInt(origPcOffset).
+ putInt(unsafeAccess);
+ // @formatter:on
+
+ NativeOrderOutputStream.PatchableInt pcDescOffset = metadataStream.patchableInt();
+ NativeOrderOutputStream.PatchableInt scopeOffset = metadataStream.patchableInt();
+ NativeOrderOutputStream.PatchableInt relocationOffset = metadataStream.patchableInt();
+ NativeOrderOutputStream.PatchableInt exceptionOffset = metadataStream.patchableInt();
+ NativeOrderOutputStream.PatchableInt implictTableOffset = null;
+ if (implicitExceptionBytes != null) {
+ implictTableOffset = metadataStream.patchableInt();
+ }
+ NativeOrderOutputStream.PatchableInt oopMapOffset = metadataStream.patchableInt();
+ metadataStream.align(8);
+
+ pcDescOffset.set(metadataStream.position());
+ metadataStream.put(pcDesc).align(8);
+
+ scopeOffset.set(metadataStream.position());
+ metadataStream.put(scopeDesc).align(8);
+
+ relocationOffset.set(metadataStream.position());
+ metadataStream.put(relocationInfo).align(8);
+
+ exceptionOffset.set(metadataStream.position());
+ metadataStream.put(exceptionBytes).align(8);
+
+ if (implicitExceptionBytes != null) {
+ implictTableOffset.set(metadataStream.position());
+ metadataStream.put(implicitExceptionBytes).align(8);
+ }
+
+ // oopmaps should be last
+ oopMapOffset.set(metadataStream.position());
+ metadataStream.put(oopMapInfo).align(8);
+
+ totalSize.set(metadataStream.position());
+
+ byte[] data = metadataStream.array();
+
+ methodMetadataContainer.appendBytes(data, 0, data.length);
+ } catch (Exception e) {
+ throw new InternalError("Exception occurred during compilation of " + methodInfo.getMethodInfo().getSymbolName(), e);
+ }
+ methodInfo.clearCompileData(); // Clear unused anymore compilation data
+ }
+ }
+
+ private static int addMetadataEntries(BinaryContainer binaryContainer, HotSpotMetaData metaData, CompiledMethodInfo methodInfo) {
+ Object[] metaDataEntries = metaData.metadataEntries();
+
+ if (metaDataEntries.length == 0) {
+ return 0;
+ }
+
+ int metadataGotSlotsStart = binaryContainer.getMetadataGotContainer().getByteStreamSize(); // binaryContainer.reserveMetadataGOTSlots(metaDataEntries.length);
+
+ for (int index = 0; index < metaDataEntries.length; index++) {
+ Object ref = metaDataEntries[index];
+ String name = metadataName(ref);
+ // Create GOT cells for klasses referenced in metadata
+ addMetadataEntry(binaryContainer, name);
+ // We should already have added entries for this klass
+ assert AOTCompiledClass.getAOTKlassData(getType(ref)) != null;
+ assert methodInfo.getDependentKlassData(getType(ref)) != null;
+ }
+
+ return metadataGotSlotsStart;
+ }
+
+ private static void addMetadataEntry(BinaryContainer binaryContainer, String name) {
+ int stringOffset = binaryContainer.addMetaspaceName(name);
+ binaryContainer.addMetadataGotEntry(stringOffset);
+ }
+
+ /**
+ * Process {@link Infopoint}s, {@link Mark}s and {@link DataPatch}es generated by the compiler
+ * to create all needed binary section constructs.
+ *
+ * @param compiledClass compilation result
+ */
+ private void processInfopointsAndMarks(AOTCompiledClass compiledClass) {
+ ArrayList<CompiledMethodInfo> compiledMethods = compiledClass.getCompiledMethods();
+
+ MarkProcessor markProcessor = new MarkProcessor(dataBuilder);
+ DataPatchProcessor dataPatchProcessor = new DataPatchProcessor(dataBuilder);
+ InfopointProcessor infopointProcessor = new InfopointProcessor(dataBuilder);
+
+ for (CompiledMethodInfo methodInfo : compiledMethods) {
+ CompilationResult compilationResult = methodInfo.getCompilationResult();
+ String targetSymbol = "state.M" + methodInfo.getCodeId();
+ String gotName = "got." + targetSymbol;
+ GotSymbol symbol = binaryContainer.getMethodStateContainer().createGotSymbol(gotName);
+ assert (symbol.getIndex() == methodInfo.getCodeId()) : "wrong offset";
+
+ for (Infopoint infoPoint : compilationResult.getInfopoints()) {
+ infopointProcessor.process(methodInfo, infoPoint);
+ }
+
+ for (CompilationResult.CodeMark mark : compilationResult.getMarks()) {
+ markProcessor.process(methodInfo, mark);
+ }
+
+ for (DataPatch dataPatch : compilationResult.getDataPatches()) {
+ dataPatchProcessor.process(methodInfo, dataPatch);
+ }
+ }
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Options.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Options.java
new file mode 100644
index 000000000..e5dcda118
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Options.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import jdk.tools.jaotc.collect.ClassSearch;
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.SearchFor;
+import jdk.tools.jaotc.collect.SearchPath;
+import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider;
+import jdk.tools.jaotc.collect.directory.DirectorySourceProvider;
+import jdk.tools.jaotc.collect.jar.JarSourceProvider;
+import jdk.tools.jaotc.collect.module.ModuleSourceProvider;
+
+final class Options {
+ List<SearchFor> files = new LinkedList<>();
+ String osName;
+ String outputName = defaultOutputName();
+ String methodList;
+ List<ClassSource> sources = new ArrayList<>();
+ String linkerpath = null;
+ SearchPath searchPath = new SearchPath();
+
+ /**
+ * We don't see scaling beyond 16 threads.
+ */
+ private static final int COMPILER_THREADS = 16;
+
+ int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors());
+
+ boolean ignoreClassLoadingErrors;
+ boolean exitOnError;
+ boolean info;
+ boolean verbose;
+ boolean debug;
+ boolean help;
+ boolean version;
+ boolean compileWithAssertions;
+ boolean tiered;
+
+ private String defaultOutputName() {
+ osName = System.getProperty("os.name");
+ String name = "unnamed.";
+ String ext;
+
+ switch (osName) {
+ case "Linux":
+ ext = "so";
+ break;
+ case "Mac OS X":
+ ext = "dylib";
+ break;
+ default:
+ if (osName.startsWith("Windows")) {
+ ext = "dll";
+ } else {
+ ext = "so";
+ }
+ }
+
+ return name + ext;
+ }
+
+ static class BadArgs extends Exception {
+ private static final long serialVersionUID = 1L;
+ final String key;
+ final Object[] args;
+ boolean showUsage;
+
+ BadArgs(String key, Object... args) {
+ super(MessageFormat.format(key, args));
+ this.key = key;
+ this.args = args;
+ }
+
+ BadArgs showUsage(boolean b) {
+ showUsage = b;
+ return this;
+ }
+ }
+
+ abstract static class Option {
+ final String help;
+ final boolean hasArg;
+ final String[] aliases;
+
+ Option(String help, boolean hasArg, String... aliases) {
+ this.help = help;
+ this.hasArg = hasArg;
+ this.aliases = aliases;
+ }
+
+ boolean isHidden() {
+ return false;
+ }
+
+ boolean matches(String opt) {
+ for (String a : aliases) {
+ if (a.equals(opt)) {
+ return true;
+ } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ boolean ignoreRest() {
+ return false;
+ }
+
+ abstract void process(Main task, String opt, String arg) throws BadArgs;
+ }
+
+ static Option[] recognizedOptions = {new Option(" --output <file> Output file name", true, "--output") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ String name = arg;
+ task.options.outputName = name;
+ }
+ }, new Option(" --class-name <class names> List of classes to compile", true, "--class-name", "--classname") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ task.options.files.addAll(ClassSearch.makeList(ClassNameSourceProvider.TYPE, arg));
+ }
+ }, new Option(" --jar <jarfiles> List of jar files to compile", true, "--jar") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ task.options.files.addAll(ClassSearch.makeList(JarSourceProvider.TYPE, arg));
+ }
+ }, new Option(" --module <modules> List of modules to compile", true, "--module") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ task.options.files.addAll(ClassSearch.makeList(ModuleSourceProvider.TYPE, arg));
+ }
+ }, new Option(" --directory <dirs> List of directories where to search for files to compile", true, "--directory") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ task.options.files.addAll(ClassSearch.makeList(DirectorySourceProvider.TYPE, arg));
+ }
+ }, new Option(" --search-path <dirs> List of directories where to search for specified files", true, "--search-path") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ String[] elements = arg.split(":");
+ task.options.searchPath.add(elements);
+ }
+ }, new Option(" --compile-commands <file> Name of file with compile commands", true, "--compile-commands") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ task.options.methodList = arg;
+ }
+ }, new Option(" --compile-for-tiered Generate profiling code for tiered compilation", false, "--compile-for-tiered") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ task.options.tiered = true;
+ }
+ }, new Option(" --compile-with-assertions Compile with java assertions", false, "--compile-with-assertions") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ task.options.compileWithAssertions = true;
+ }
+ }, new Option(" --compile-threads <number> Number of compilation threads to be used", true, "--compile-threads", "--threads") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ int threads = Integer.parseInt(arg);
+ final int available = Runtime.getRuntime().availableProcessors();
+ if (threads <= 0) {
+ task.warning("invalid number of threads specified: {0}, using: {1}", threads, available);
+ threads = available;
+ }
+ if (threads > available) {
+ task.warning("too many threads specified: {0}, limiting to: {1}", threads, available);
+ }
+ task.options.threads = Integer.min(threads, available);
+ }
+ }, new Option(" --ignore-errors Ignores all exceptions thrown during class loading", false, "--ignore-errors") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ task.options.ignoreClassLoadingErrors = true;
+ }
+ }, new Option(" --exit-on-error Exit on compilation errors", false, "--exit-on-error") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ task.options.exitOnError = true;
+ }
+ }, new Option(" --info Print information during compilation", false, "--info") {
+ @Override
+ void process(Main task, String opt, String arg) throws BadArgs {
+ task.options.info = true;
+ }
+ }, new Option(" --verbose Print verbose information", false, "--verbose") {
+ @Override
+ void process(Main task, String opt, String arg) throws BadArgs {
+ task.options.info = true;
+ task.options.verbose = true;
+ }
+ }, new Option(" --debug Print debug information", false, "--debug") {
+ @Override
+ void process(Main task, String opt, String arg) throws BadArgs {
+ task.options.info = true;
+ task.options.verbose = true;
+ task.options.debug = true;
+ }
+ }, new Option(" -? -h --help Print this help message", false, "--help", "-h", "-?") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ task.options.help = true;
+ }
+ }, new Option(" --version Version information", false, "--version") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ task.options.version = true;
+ }
+ }, new Option(" --linker-path Full path to linker executable", true, "--linker-path") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ task.options.linkerpath = arg;
+ }
+ }, new Option(" -J<flag> Pass <flag> directly to the runtime system", false, "-J") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ }
+ }};
+
+ static void handleOptions(Main task, String[] args) throws BadArgs {
+ if (args.length == 0) {
+ task.options.help = true;
+ return;
+ }
+
+ // Make checkstyle happy.
+ int i = 0;
+ while (i < args.length) {
+ String arg = args[i];
+
+ if (arg.charAt(0) == '-') {
+ Option option = getOption(arg);
+ String param = null;
+
+ if (option.hasArg) {
+ if (arg.startsWith("--") && arg.indexOf('=') > 0) {
+ param = arg.substring(arg.indexOf('=') + 1, arg.length());
+ } else if (i + 1 < args.length) {
+ param = args[++i];
+ }
+
+ if (param == null || param.isEmpty() || param.charAt(0) == '-') {
+ throw new BadArgs("missing argument for option: {0}", arg).showUsage(true);
+ }
+ }
+
+ option.process(task, arg, param);
+
+ if (option.ignoreRest()) {
+ break;
+ }
+ } else {
+ task.options.files.add(new SearchFor(arg));
+ }
+ i++;
+ }
+ }
+
+ static Option getOption(String name) throws BadArgs {
+ for (Option o : recognizedOptions) {
+ if (o.matches(name)) {
+ return o;
+ }
+ }
+ throw new BadArgs("unknown option: {0}", name).showUsage(true);
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubDirectCallSiteRelocationSymbol.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubDirectCallSiteRelocationSymbol.java
new file mode 100644
index 000000000..e41987ab4
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubDirectCallSiteRelocationSymbol.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+
+/**
+ * Call to a Graal stub, the symbol name should be direct.
+ */
+final class StubDirectCallSiteRelocationSymbol extends CallSiteRelocationSymbol {
+
+ StubDirectCallSiteRelocationSymbol(CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) {
+ super(binaryContainer.getSymbol(callSiteRelocation.targetSymbol));
+ assert symbol != null && symbol.getBinding() == Binding.LOCAL : "Stub symbol must exist and must be LOCAL";
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubInformation.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubInformation.java
new file mode 100644
index 000000000..53e701abf
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubInformation.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+public final class StubInformation {
+ private int stubOffset; // the offset inside the code (text + stubOffset)
+ private int stubSize; // the stub size
+ private int dispatchJumpOffset; // offset after main dispatch jump instruction
+ private int resolveJumpOffset; // offset after jump instruction to runtime call resolution
+ // function.
+ private int resolveJumpStart; // offset of jump instruction to VM runtime call resolution
+ // function.
+ private int c2iJumpOffset; // offset after jump instruction to c2i adapter for static
+ // calls.
+ private int movOffset; // offset after move instruction which loads from got cell:
+ // - Method* for static call
+ // - Klass* for virtual call
+
+ private boolean isVirtual; // virtual call stub
+
+ // maybe add type of stub as well, right now we only have static stubs
+
+ StubInformation(int stubOffset, boolean isVirtual) {
+ this.stubOffset = stubOffset;
+ this.isVirtual = isVirtual;
+ this.stubSize = -1;
+ this.movOffset = -1;
+ this.c2iJumpOffset = -1;
+ this.resolveJumpOffset = -1;
+ this.resolveJumpStart = -1;
+ this.dispatchJumpOffset = -1;
+ }
+
+ int getOffset() {
+ return stubOffset;
+ }
+
+ boolean isVirtual() {
+ return isVirtual;
+ }
+
+ public void setSize(int stubSize) {
+ this.stubSize = stubSize;
+ }
+
+ int getSize() {
+ return stubSize;
+ }
+
+ public void setMovOffset(int movOffset) {
+ this.movOffset = movOffset + stubOffset;
+ }
+
+ int getMovOffset() {
+ return movOffset;
+ }
+
+ public void setC2IJumpOffset(int c2iJumpOffset) {
+ this.c2iJumpOffset = c2iJumpOffset + stubOffset;
+ }
+
+ int getC2IJumpOffset() {
+ return c2iJumpOffset;
+ }
+
+ public void setResolveJumpOffset(int resolveJumpOffset) {
+ this.resolveJumpOffset = resolveJumpOffset + stubOffset;
+ }
+
+ int getResolveJumpOffset() {
+ return resolveJumpOffset;
+ }
+
+ public void setResolveJumpStart(int resolveJumpStart) {
+ this.resolveJumpStart = resolveJumpStart + stubOffset;
+ }
+
+ int getResolveJumpStart() {
+ return resolveJumpStart;
+ }
+
+ public void setDispatchJumpOffset(int dispatchJumpOffset) {
+ this.dispatchJumpOffset = dispatchJumpOffset + stubOffset;
+ }
+
+ int getDispatchJumpOffset() {
+ return dispatchJumpOffset;
+ }
+
+ void verify() {
+ assert stubOffset > 0 : "incorrect stubOffset: " + stubOffset;
+ assert stubSize > 0 : "incorrect stubSize: " + stubSize;
+ assert movOffset > 0 : "incorrect movOffset: " + movOffset;
+ assert dispatchJumpOffset > 0 : "incorrect dispatchJumpOffset: " + dispatchJumpOffset;
+ assert resolveJumpStart > 0 : "incorrect resolveJumpStart: " + resolveJumpStart;
+ assert resolveJumpOffset > 0 : "incorrect resolveJumpOffset: " + resolveJumpOffset;
+ if (!isVirtual) {
+ assert c2iJumpOffset > 0 : "incorrect c2iJumpOffset: " + c2iJumpOffset;
+ }
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Timer.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Timer.java
new file mode 100644
index 000000000..e7f81b5ef
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Timer.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc;
+
+final class Timer implements AutoCloseable {
+
+ private final Main main;
+ private final long start;
+
+ Timer(Main main, String message) {
+ this.main = main;
+ start = System.currentTimeMillis();
+ main.printer.printInfo(message);
+ }
+
+ @Override
+ public void close() {
+ final long end = System.currentTimeMillis();
+ main.printer.printlnInfo(" (" + (end - start) + " ms)");
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/aarch64/AArch64ELFMacroAssembler.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/aarch64/AArch64ELFMacroAssembler.java
new file mode 100644
index 000000000..c3d28cae2
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/aarch64/AArch64ELFMacroAssembler.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2023, Red Hat Inc. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.aarch64;
+
+import static jdk.vm.ci.aarch64.AArch64.r12;
+import static jdk.vm.ci.aarch64.AArch64.r16;
+import static jdk.vm.ci.aarch64.AArch64.r17;
+import static jdk.vm.ci.aarch64.AArch64.r9;
+
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+
+import jdk.tools.jaotc.ELFMacroAssembler;
+import jdk.tools.jaotc.StubInformation;
+import jdk.vm.ci.code.TargetDescription;
+
+public final class AArch64ELFMacroAssembler extends AArch64MacroAssembler implements ELFMacroAssembler {
+
+ private int currentEndOfInstruction;
+
+ public AArch64ELFMacroAssembler(TargetDescription target) {
+ super(target);
+ }
+
+ @Override
+ public int currentEndOfInstruction() {
+ return currentEndOfInstruction;
+ }
+
+ @Override
+ public byte[] getPLTJumpCode() {
+ // The main dispatch instruction
+ addressOf(r16);
+ ldr(64, r16, AArch64Address.createBaseRegisterOnlyAddress(r16));
+ jmp(r16);
+
+ currentEndOfInstruction = position();
+
+ align(8);
+
+ return close(true);
+ }
+
+ @Override
+ public byte[] getPLTStaticEntryCode(StubInformation stub) {
+ // The main dispatch instruction
+ addressOf(r16);
+ ldr(64, r16, AArch64Address.createBaseRegisterOnlyAddress(r16));
+ jmp(r16);
+ stub.setDispatchJumpOffset(position());
+
+ // C2I stub used to call interpreter. First load r12
+ // (i.e. rmethod) with a pointer to the Method structure ...
+ addressOf(r12);
+ ldr(64, r12, AArch64Address.createBaseRegisterOnlyAddress(r12));
+ nop();
+ stub.setMovOffset(position());
+
+ // ... then jump to the interpreter.
+ addressOf(r16);
+ ldr(64, r16, AArch64Address.createBaseRegisterOnlyAddress(r16));
+ jmp(r16);
+ stub.setC2IJumpOffset(position());
+
+ // Call to VM runtime to resolve the call.
+ stub.setResolveJumpStart(position());
+ addressOf(r16);
+ ldr(64, r16, AArch64Address.createBaseRegisterOnlyAddress(r16));
+ jmp(r16);
+ stub.setResolveJumpOffset(position());
+ currentEndOfInstruction = position();
+
+ align(8);
+ stub.setSize(position());
+
+ return close(true);
+ }
+
+ @Override
+ public byte[] getPLTVirtualEntryCode(StubInformation stub) {
+ // Fixup an inline cache.
+ // Load r9 with a pointer to the Klass.
+ addressOf(r17);
+ ldr(64, r9, AArch64Address.createBaseRegisterOnlyAddress(r17));
+ nop();
+ stub.setMovOffset(position());
+
+ // Jump to the method.
+ addressOf(r16);
+ ldr(64, r16, AArch64Address.createBaseRegisterOnlyAddress(r16));
+ jmp(r16);
+ stub.setDispatchJumpOffset(position());
+
+ // Call to VM runtime to resolve the call.
+ stub.setResolveJumpStart(position());
+ addressOf(r16);
+ ldr(64, r16, AArch64Address.createBaseRegisterOnlyAddress(r16));
+ jmp(r16);
+ stub.setResolveJumpOffset(position());
+ currentEndOfInstruction = position();
+
+ align(8);
+ stub.setSize(position());
+
+ return close(true);
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/aarch64/AArch64InstructionDecoder.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/aarch64/AArch64InstructionDecoder.java
new file mode 100644
index 000000000..a6979061a
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/aarch64/AArch64InstructionDecoder.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2023, Red Hat Inc. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.aarch64;
+
+import jdk.tools.jaotc.InstructionDecoder;
+
+public final class AArch64InstructionDecoder extends InstructionDecoder {
+
+ private int currentEndOfInstruction;
+
+ public AArch64InstructionDecoder() {
+ }
+
+ @Override
+ public int currentEndOfInstruction() {
+ return currentEndOfInstruction;
+ }
+
+ @Override
+ public void decodePosition(final byte[] code, int pcOffset) {
+ currentEndOfInstruction = pcOffset + 4;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64ELFMacroAssembler.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64ELFMacroAssembler.java
new file mode 100644
index 000000000..0f28a365b
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64ELFMacroAssembler.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.amd64;
+
+import static jdk.vm.ci.amd64.AMD64.rax;
+import static jdk.vm.ci.amd64.AMD64.rbx;
+import static jdk.vm.ci.amd64.AMD64.rip;
+
+import jdk.tools.jaotc.StubInformation;
+import jdk.tools.jaotc.ELFMacroAssembler;
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+
+import jdk.vm.ci.code.TargetDescription;
+import org.graalvm.compiler.options.OptionValues;
+
+public final class AMD64ELFMacroAssembler extends AMD64MacroAssembler implements ELFMacroAssembler {
+
+ private int currentEndOfInstruction;
+
+ public AMD64ELFMacroAssembler(TargetDescription target, OptionValues optionValues) {
+ super(target, optionValues);
+ }
+
+ @Override
+ public int currentEndOfInstruction() {
+ return currentEndOfInstruction;
+ }
+
+ @Override
+ public byte[] getPLTJumpCode() {
+ // The main dispatch instruction
+ // jmpq *0x00000000(%rip)
+ jmp(new AMD64Address(rip, 0));
+ currentEndOfInstruction = position();
+
+ // Align to 8 bytes
+ align(8);
+
+ return close(true);
+ }
+
+ @Override
+ public byte[] getPLTStaticEntryCode(StubInformation stub) {
+ // The main dispatch instruction
+ // jmpq *0x00000000(%rip)
+ jmp(new AMD64Address(rip, 0));
+ stub.setDispatchJumpOffset(position());
+
+ // C2I stub used to call interpreter.
+ // mov 0x00000000(%rip),%rbx Loading Method*
+ movq(rbx, new AMD64Address(rip, 0));
+ stub.setMovOffset(position());
+
+ // jmpq *0x00000000(%rip) [c2i addr]
+ jmp(new AMD64Address(rip, 0));
+ stub.setC2IJumpOffset(position());
+
+ // Call to VM runtime to resolve the call.
+ // jmpq *0x00000000(%rip)
+ stub.setResolveJumpStart(position());
+ jmp(new AMD64Address(rip, 0));
+ stub.setResolveJumpOffset(position());
+ currentEndOfInstruction = position();
+
+ // Align to 8 bytes
+ align(8);
+ stub.setSize(position());
+
+ return close(true);
+ }
+
+ @Override
+ public byte[] getPLTVirtualEntryCode(StubInformation stub) {
+ // Klass loading instruction
+ // mov 0x00000000(%rip),%rax
+ movq(rax, new AMD64Address(rip, 0));
+ stub.setMovOffset(position());
+
+ // The main dispatch instruction
+ // jmpq *0x00000000(%rip)
+ jmp(new AMD64Address(rip, 0));
+ stub.setDispatchJumpOffset(position());
+
+ // Call to VM runtime to resolve the call.
+ // jmpq *0x00000000(%rip)
+ stub.setResolveJumpStart(position());
+ jmp(new AMD64Address(rip, 0));
+ stub.setResolveJumpOffset(position());
+ currentEndOfInstruction = position();
+
+ // Align to 8 bytes
+ align(8);
+ stub.setSize(position());
+
+ return close(true);
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64InstructionDecoder.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64InstructionDecoder.java
new file mode 100644
index 000000000..8c950b83e
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64InstructionDecoder.java
@@ -0,0 +1,569 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.amd64;
+
+import jdk.tools.jaotc.InstructionDecoder;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public final class AMD64InstructionDecoder extends InstructionDecoder {
+
+ private boolean targetIs64Bit;
+ private int currentEndOfInstruction;
+
+ private static class Prefix {
+
+ // segment overrides
+ static final int CSSegment = 0x2e;
+ static final int SSSegment = 0x36;
+ static final int DSSegment = 0x3e;
+ static final int ESSegment = 0x26;
+ static final int FSSegment = 0x64;
+ static final int GSSegment = 0x65;
+ static final int REX = 0x40;
+ static final int REXB = 0x41;
+ static final int REXX = 0x42;
+ static final int REXXB = 0x43;
+ static final int REXR = 0x44;
+ static final int REXRB = 0x45;
+ static final int REXRX = 0x46;
+ static final int REXRXB = 0x47;
+ static final int REXW = 0x48;
+ static final int REXWB = 0x49;
+ static final int REXWX = 0x4A;
+ static final int REXWXB = 0x4B;
+ static final int REXWR = 0x4C;
+ static final int REXWRB = 0x4D;
+ static final int REXWRX = 0x4E;
+ static final int REXWRXB = 0x4F;
+ static final int VEX_3BYTES = 0xC4;
+ static final int VEX_2BYTES = 0xC5;
+ }
+
+ @SuppressWarnings("unused")
+ private static class VexPrefix {
+ static final int VEX_R = 0x80;
+ static final int VEX_W = 0x80;
+ }
+
+ @SuppressWarnings("unused")
+ private static class VexOpcode {
+ static final int VEX_OPCODE_NONE = 0x0;
+ static final int VEX_OPCODE_0F = 0x1;
+ static final int VEX_OPCODE_0F_38 = 0x2;
+ static final int VEX_OPCODE_0F_3A = 0x3;
+ static final int VEX_OPCODE_MASK = 0x1F;
+ }
+
+ public AMD64InstructionDecoder(TargetDescription target) {
+ this.targetIs64Bit = target.wordSize == 8;
+ }
+
+ @Override
+ public int currentEndOfInstruction() {
+ return currentEndOfInstruction;
+ }
+
+ @Override
+ @SuppressWarnings("fallthrough")
+ public void decodePosition(final byte[] code, int pcOffset) {
+ assert pcOffset >= 0 && pcOffset < code.length;
+
+ // Decode the given instruction, and return the Pointer of
+ // an embedded 32-bit operand word.
+
+ // If "which" is WhichOperand.disp32operand, selects the displacement portion
+ // of an effective Pointer specifier.
+ // If "which" is imm64Operand, selects the trailing immediate constant.
+ // If "which" is WhichOperand.call32operand, selects the displacement of a call or jump.
+ // Caller is responsible for ensuring that there is such an operand,
+ // and that it is 32/64 bits wide.
+
+ // If "which" is endPcOperand, find the end of the instruction.
+
+ int ip = pcOffset;
+ boolean is64bit = false;
+
+ boolean hasDisp32 = false;
+ int tailSize = 0; // other random bytes (#32, #16, etc.) at end of insn
+
+ boolean againAfterPrefix = true;
+
+ while (againAfterPrefix) {
+ againAfterPrefix = false;
+ switch (0xFF & code[ip++]) {
+
+ // These convenience macros generate groups of "case" labels for the switch.
+
+ case Prefix.CSSegment:
+ case Prefix.SSSegment:
+ case Prefix.DSSegment:
+ case Prefix.ESSegment:
+ case Prefix.FSSegment:
+ case Prefix.GSSegment:
+ // Seems dubious
+ assert !targetIs64Bit : "shouldn't have that prefix";
+ assert ip == pcOffset + 1 : "only one prefix allowed";
+ againAfterPrefix = true;
+ break;
+
+ case 0x67:
+ case Prefix.REX:
+ case Prefix.REXB:
+ case Prefix.REXX:
+ case Prefix.REXXB:
+ case Prefix.REXR:
+ case Prefix.REXRB:
+ case Prefix.REXRX:
+ case Prefix.REXRXB:
+ assert targetIs64Bit : "64bit prefixes";
+ againAfterPrefix = true;
+ break;
+
+ case Prefix.REXW:
+ case Prefix.REXWB:
+ case Prefix.REXWX:
+ case Prefix.REXWXB:
+ case Prefix.REXWR:
+ case Prefix.REXWRB:
+ case Prefix.REXWRX:
+ case Prefix.REXWRXB:
+ assert targetIs64Bit : "64bit prefixes";
+ is64bit = true;
+ againAfterPrefix = true;
+ break;
+
+ case 0xFF: // pushq a; decl a; incl a; call a; jmp a
+ case 0x88: // movb a, r
+ case 0x89: // movl a, r
+ case 0x8A: // movb r, a
+ case 0x8B: // movl r, a
+ case 0x8F: // popl a
+ hasDisp32 = true;
+ break;
+
+ case 0x68: // pushq #32
+ currentEndOfInstruction = ip + 4;
+ return; // not produced by emitOperand
+
+ case 0x66: // movw ... (size prefix)
+ boolean againAfterSizePrefix2 = true;
+ while (againAfterSizePrefix2) {
+ againAfterSizePrefix2 = false;
+ switch (0xFF & code[ip++]) {
+ case Prefix.REX:
+ case Prefix.REXB:
+ case Prefix.REXX:
+ case Prefix.REXXB:
+ case Prefix.REXR:
+ case Prefix.REXRB:
+ case Prefix.REXRX:
+ case Prefix.REXRXB:
+ case Prefix.REXW:
+ case Prefix.REXWB:
+ case Prefix.REXWX:
+ case Prefix.REXWXB:
+ case Prefix.REXWR:
+ case Prefix.REXWRB:
+ case Prefix.REXWRX:
+ case Prefix.REXWRXB:
+ assert targetIs64Bit : "64bit prefix found";
+ againAfterSizePrefix2 = true;
+ break;
+ case 0x8B: // movw r, a
+ case 0x89: // movw a, r
+ hasDisp32 = true;
+ break;
+ case 0xC7: // movw a, #16
+ hasDisp32 = true;
+ tailSize = 2; // the imm16
+ break;
+ case 0x0F: // several SSE/SSE2 variants
+ ip--; // reparse the 0x0F
+ againAfterPrefix = true;
+ break;
+ default:
+ throw new InternalError("should not reach here");
+ }
+ }
+ break;
+
+ case 0xB8: // movl/q r, #32/#64(oop?)
+ case 0xB9:
+ case 0xBA:
+ case 0xBB:
+ case 0xBC:
+ case 0xBD:
+ case 0xBE:
+ case 0xBF:
+ currentEndOfInstruction = ip + (is64bit ? 8 : 4);
+ return;
+
+ case 0x69: // imul r, a, #32
+ case 0xC7: // movl a, #32(oop?)
+ tailSize = 4;
+ hasDisp32 = true; // has both kinds of operands!
+ break;
+
+ case 0x0F: // movx..., etc.
+ switch (0xFF & code[ip++]) {
+ case 0x3A: // pcmpestri
+ ip++; // skip opcode
+ tailSize = 1;
+ hasDisp32 = true; // has both kinds of operands!
+ break;
+
+ case 0x38: // ptest, pmovzxbw
+ ip++; // skip opcode
+ hasDisp32 = true; // has both kinds of operands!
+ break;
+
+ case 0x70: // pshufd r, r/a, #8
+ hasDisp32 = true; // has both kinds of operands!
+ tailSize = 1;
+ break;
+
+ case 0x73: // psrldq r, #8
+ tailSize = 1;
+ break;
+
+ case 0x12: // movlps
+ case 0x28: // movaps
+ case 0x2E: // ucomiss
+ case 0x2F: // comiss
+ case 0x54: // andps
+ case 0x55: // andnps
+ case 0x56: // orps
+ case 0x57: // xorps
+ case 0x58: // addpd
+ case 0x59: // mulpd
+ case 0x6E: // movd
+ case 0x7E: // movd
+ case 0xAE: // ldmxcsr, stmxcsr, fxrstor, fxsave, clflush
+ case 0xFE: // paddd
+ // 64bit side says it these have both operands but that doesn't
+ // appear to be true
+ hasDisp32 = true;
+ break;
+
+ case 0xAD: // shrd r, a, %cl
+ case 0xAF: // imul r, a
+ case 0xBE: // movsbl r, a (movsxb)
+ case 0xBF: // movswl r, a (movsxw)
+ case 0xB6: // movzbl r, a (movzxb)
+ case 0xB7: // movzwl r, a (movzxw)
+ case 0x40: // cmovl cc, r, a
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ case 0x48:
+ case 0x49:
+ case 0x4A:
+ case 0x4B:
+ case 0x4C:
+ case 0x4D:
+ case 0x4E:
+ case 0x4F:
+ case 0xB0: // cmpxchgb
+ case 0xB1: // cmpxchg
+ case 0xC1: // xaddl
+ case 0xC7: // cmpxchg8
+ case 0x90: // setcc a
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ case 0x98:
+ case 0x99:
+ case 0x9A:
+ case 0x9B:
+ case 0x9C:
+ case 0x9D:
+ case 0x9E:
+ case 0x9F:
+ hasDisp32 = true;
+ // fall out of the switch to decode the Pointer
+ break;
+
+ case 0xC4: // pinsrw r, a, #8
+ hasDisp32 = true;
+ tailSize = 1; // the imm8
+ break;
+
+ case 0xC5: // pextrw r, r, #8
+ tailSize = 1; // the imm8
+ break;
+
+ case 0xAC: // shrd r, a, #8
+ hasDisp32 = true;
+ tailSize = 1; // the imm8
+ break;
+
+ case 0x80: // jcc rdisp32
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8A:
+ case 0x8B:
+ case 0x8C:
+ case 0x8D:
+ case 0x8E:
+ case 0x8F:
+ currentEndOfInstruction = ip + 4;
+ return;
+ default:
+ throw new InternalError("should not reach here");
+ }
+ break;
+
+ case 0x81: // addl a, #32; addl r, #32
+ // also: orl, adcl, sbbl, andl, subl, xorl, cmpl
+ // on 32bit in the case of cmpl, the imm might be an oop
+ tailSize = 4;
+ hasDisp32 = true; // has both kinds of operands!
+ break;
+
+ case 0x83: // addl a, #8; addl r, #8
+ // also: orl, adcl, sbbl, andl, subl, xorl, cmpl
+ hasDisp32 = true; // has both kinds of operands!
+ tailSize = 1;
+ break;
+
+ case 0x9B:
+ switch (0xFF & code[ip++]) {
+ case 0xD9: // fnstcw a
+ hasDisp32 = true;
+ break;
+ default:
+ throw new InternalError("should not reach here");
+ }
+ break;
+
+ case 0x00: // addb a, r; addl a, r; addb r, a; addl r, a
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x10: // adc...
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x20: // and...
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x30: // xor...
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x08: // or...
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x18: // sbb...
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x28: // sub...
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0xF7: // mull a
+ case 0x8D: // lea r, a
+ case 0x87: // xchg r, a
+ case 0x38: // cmp...
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x85: // test r, a
+ hasDisp32 = true; // has both kinds of operands!
+ break;
+
+ case 0xC1: // sal a, #8; sar a, #8; shl a, #8; shr a, #8
+ case 0xC6: // movb a, #8
+ case 0x80: // cmpb a, #8
+ case 0x6B: // imul r, a, #8
+ hasDisp32 = true; // has both kinds of operands!
+ tailSize = 1; // the imm8
+ break;
+
+ case Prefix.VEX_3BYTES:
+ case Prefix.VEX_2BYTES:
+ assert ip == pcOffset + 1 : "no prefixes allowed";
+ int vexOpcode;
+ // First byte
+ if ((code[pcOffset] & 0xFF) == Prefix.VEX_3BYTES) {
+ vexOpcode = VexOpcode.VEX_OPCODE_MASK & code[ip];
+ ip++; // third byte
+ is64bit = ((VexPrefix.VEX_W & code[ip]) == VexPrefix.VEX_W);
+ } else {
+ vexOpcode = VexOpcode.VEX_OPCODE_0F;
+ }
+ ip++; // opcode
+ // To find the end of instruction (which == end_pc_operand).
+ switch (vexOpcode) {
+ case VexOpcode.VEX_OPCODE_0F:
+ switch (0xFF & code[ip]) {
+ case 0x70: // pshufd r, r/a, #8
+ case 0x71: // ps[rl|ra|ll]w r, #8
+ case 0x72: // ps[rl|ra|ll]d r, #8
+ case 0x73: // ps[rl|ra|ll]q r, #8
+ case 0xC2: // cmp[ps|pd|ss|sd] r, r, r/a, #8
+ case 0xC4: // pinsrw r, r, r/a, #8
+ case 0xC5: // pextrw r/a, r, #8
+ case 0xC6: // shufp[s|d] r, r, r/a, #8
+ tailSize = 1; // the imm8
+ break;
+ default:
+ break; // no imm8
+ }
+ break;
+ case VexOpcode.VEX_OPCODE_0F_3A:
+ tailSize = 1;
+ break;
+ default:
+ throw new InternalError("should not reach here");
+ }
+ ip++; // skip opcode
+ hasDisp32 = true;
+ break;
+
+ case 0xE8: // call rdisp32
+ case 0xE9: // jmp rdisp32
+ currentEndOfInstruction = ip + 4;
+ return;
+
+ case 0xD1: // sal a, 1; sar a, 1; shl a, 1; shr a, 1
+ case 0xD3: // sal a, %cl; sar a, %cl; shl a, %cl; shr a, %cl
+ case 0xD9: // fldS a; fstS a; fstpS a; fldcw a
+ case 0xDD: // fldD a; fstD a; fstpD a
+ case 0xDB: // fildS a; fistpS a; fldX a; fstpX a
+ case 0xDF: // fildD a; fistpD a
+ case 0xD8: // faddS a; fsubrS a; fmulS a; fdivrS a; fcompS a
+ case 0xDC: // faddD a; fsubrD a; fmulD a; fdivrD a; fcompD a
+ case 0xDE: // faddpD a; fsubrpD a; fmulpD a; fdivrpD a; fcomppD a
+ hasDisp32 = true;
+ break;
+
+ case 0xF0: // Lock
+ againAfterPrefix = true;
+ break;
+
+ case 0xF3: // For SSE
+ case 0xF2: // For SSE2
+ switch (0xFF & code[ip++]) {
+ case Prefix.REX:
+ case Prefix.REXB:
+ case Prefix.REXX:
+ case Prefix.REXXB:
+ case Prefix.REXR:
+ case Prefix.REXRB:
+ case Prefix.REXRX:
+ case Prefix.REXRXB:
+ case Prefix.REXW:
+ case Prefix.REXWB:
+ case Prefix.REXWX:
+ case Prefix.REXWXB:
+ case Prefix.REXWR:
+ case Prefix.REXWRB:
+ case Prefix.REXWRX:
+ case Prefix.REXWRXB:
+ assert targetIs64Bit : "found 64bit prefix";
+ ip++;
+ ip++;
+ break;
+ default:
+ ip++;
+ }
+ hasDisp32 = true; // has both kinds of operands!
+ break;
+
+ default:
+ throw new InternalError("should not reach here");
+ }
+ }
+
+ assert hasDisp32 : "(tw) not sure if this holds: instruction has no disp32 field";
+
+ // parse the output of emitOperand
+ int op2 = 0xFF & code[ip++];
+ int base = op2 & 0x07;
+ int op3 = -1;
+ int b100 = 4;
+ int b101 = 5;
+ if (base == b100 && (op2 >> 6) != 3) {
+ op3 = 0xFF & code[ip++];
+ base = op3 & 0x07; // refetch the base
+ }
+ // now ip points at the disp (if any)
+
+ switch (op2 >> 6) {
+ case 0:
+ // [00 reg 100][ss index base]
+ // [00 reg 100][00 100 esp]
+ // [00 reg base]
+ // [00 reg 100][ss index 101][disp32]
+ // [00 reg 101] [disp32]
+ if (base == b101) {
+ ip += 4; // skip the disp32
+ }
+ break;
+
+ case 1:
+ // [01 reg 100][ss index base][disp8]
+ // [01 reg 100][00 100 esp][disp8]
+ // [01 reg base] [disp8]
+ ip += 1; // skip the disp8
+ break;
+
+ case 2:
+ // [10 reg 100][ss index base][disp32]
+ // [10 reg 100][00 100 esp][disp32]
+ // [10 reg base] [disp32]
+ ip += 4; // skip the disp32
+ break;
+
+ case 3:
+ // [11 reg base] (not a memory addressing mode)
+ break;
+ }
+
+ currentEndOfInstruction = ip + tailSize;
+ }
+
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java
new file mode 100644
index 000000000..31533ec17
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.collect;
+
+import jdk.tools.jaotc.LoadedClass;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.io.File;
+
+public final class ClassSearch {
+ private final List<SourceProvider> providers = new ArrayList<>();
+
+ public void addProvider(SourceProvider provider) {
+ providers.add(provider);
+ }
+
+ public List<LoadedClass> search(List<SearchFor> search, SearchPath searchPath) {
+ return search(search, searchPath, (s, t) -> {
+ throw new InternalError(s + " : " + t, t);
+ });
+ }
+
+ public List<LoadedClass> search(List<SearchFor> search, SearchPath searchPath, BiConsumer<String, Throwable> classLoadingErrorsHandler) {
+ List<LoadedClass> loaded = new ArrayList<>();
+
+ List<ClassSource> sources = new ArrayList<>();
+
+ for (SearchFor entry : search) {
+ sources.add(findSource(entry, searchPath, classLoadingErrorsHandler));
+ }
+
+ for (ClassSource source : sources) {
+ if (source != null) {
+ source.eachClass((name, loader) -> {
+ LoadedClass x = loadClass(name, loader, classLoadingErrorsHandler);
+ if (x != null) {
+ loaded.add(x);
+ }
+ });
+ }
+ }
+
+ return loaded;
+ }
+
+ private static LoadedClass loadClass(String name, ClassLoader loader, BiConsumer<String, Throwable> classLoadingErrorsHandler) {
+ try {
+ Class<?> clzz = loader.loadClass(name);
+ return new LoadedClass(name, clzz);
+ } catch (Throwable e) {
+ classLoadingErrorsHandler.accept(name, e);
+ return null;
+ }
+ }
+
+ private ClassSource findSource(SearchFor searchFor, SearchPath searchPath, BiConsumer<String, Throwable> classLoadingErrorsHandler) {
+ ClassSource found = null;
+
+ for (SourceProvider provider : providers) {
+ if (!searchFor.isUnknown() && !provider.supports(searchFor.getType())) {
+ continue;
+ }
+ ClassSource source = null;
+ try {
+ source = provider.findSource(searchFor.getName(), searchPath);
+ } catch (Throwable e) {
+ classLoadingErrorsHandler.accept(searchFor.getName(), e);
+ }
+ if (source != null) {
+ if (found != null) {
+ throw new InternalError("Multiple possible sources: " + source + " and: " + found);
+ }
+ found = source;
+ }
+ }
+
+ if (found == null) {
+ classLoadingErrorsHandler.accept(searchFor.getName(), new InternalError("Failed to find " + searchFor.getType() + " file: " + searchFor.getName()));
+ }
+ return found;
+ }
+
+ public static List<SearchFor> makeList(String type, String argument) {
+ List<SearchFor> list = new ArrayList<>();
+ String[] elements = argument.split(File.pathSeparator);
+ for (String element : elements) {
+ list.add(new SearchFor(element, type));
+ }
+ return list;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java
new file mode 100644
index 000000000..16aa62c4a
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.collect;
+
+import java.nio.file.Path;
+import java.util.function.BiConsumer;
+
+public interface ClassSource {
+ static boolean pathIsClassFile(Path entry) {
+ String fileName = entry.getFileName().toString();
+ return fileName.endsWith(".class") && !fileName.endsWith("module-info.class");
+ }
+
+ static String stripRoot(Path path) {
+ if (path.getRoot() != null) {
+ String root = path.getRoot().toString();
+ String filename = path.toString().substring(root.length());
+ String separator = path.getFileSystem().getSeparator();
+ while (filename.startsWith(separator)) {
+ filename = filename.substring(separator.length());
+ }
+ return filename;
+ }
+
+ return path.toString();
+ }
+
+ static String makeClassName(Path path) {
+ String fileName = path.toString();
+
+ if (!fileName.endsWith(".class")) {
+ throw new IllegalArgumentException("File doesn't end with .class: '" + fileName + "'");
+ }
+
+ fileName = stripRoot(path);
+
+ String className = fileName.substring(0, fileName.length() - ".class".length());
+ className = className.replace(path.getFileSystem().getSeparator(), ".");
+ return className;
+ }
+
+ void eachClass(BiConsumer<String, ClassLoader> consumer);
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java
new file mode 100644
index 000000000..8b0995bff
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.collect;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashMap;
+
+public class FileSupport {
+ public boolean exists(Path path) {
+ return Files.exists(path);
+ }
+
+ public boolean isDirectory(Path path) {
+ return Files.isDirectory(path);
+ }
+
+ private static FileSystem makeJarFileSystem(Path path) {
+ try {
+ return FileSystems.newFileSystem(makeJarFileURI(path), new HashMap<>());
+ } catch (IOException e) {
+ throw new InternalError(e);
+ }
+ }
+
+ private static URI makeJarFileURI(Path path) {
+ try {
+ String name = path.toAbsolutePath().toString();
+ name = name.replace('\\', '/');
+ return new URI("jar:file", null, "///" + name + "!/", null);
+ } catch (URISyntaxException e) {
+ throw new InternalError(e);
+ }
+ }
+
+ public ClassLoader createClassLoader(Path path, ClassLoader parent) {
+ try {
+ return URLClassLoader.newInstance(buildUrls(path), parent);
+ } catch (MalformedURLException e) {
+ throw new InternalError(e);
+ }
+ }
+
+ public ClassLoader createClassLoader(Path path) throws MalformedURLException {
+ return URLClassLoader.newInstance(buildUrls(path));
+ }
+
+ private static URL[] buildUrls(Path path) throws MalformedURLException {
+ return new URL[]{path.toUri().toURL()};
+ }
+
+ public Path getJarFileSystemRoot(Path jarFile) {
+ FileSystem fileSystem = makeJarFileSystem(jarFile);
+ return fileSystem.getPath("/");
+ }
+
+ public boolean isAbsolute(Path entry) {
+ return entry.isAbsolute();
+ }
+
+ public Path getSubDirectory(FileSystem fileSystem, Path root, Path path) throws IOException {
+ DirectoryStream<Path> paths = fileSystem.provider().newDirectoryStream(root, null);
+ for (Path entry : paths) {
+ Path relative = root.relativize(entry);
+ if (relative.equals(path)) {
+ return entry;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java
new file mode 100644
index 000000000..406d27eab
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.collect;
+
+import static java.nio.file.FileVisitResult.CONTINUE;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * {@link FileVisitor} implementation to find class files recursively.
+ */
+public final class FileSystemFinder extends SimpleFileVisitor<Path> implements Iterable<Path> {
+ private final ArrayList<Path> fileNames = new ArrayList<>();
+ private final PathMatcher filter;
+
+ public FileSystemFinder(Path combinedPath, PathMatcher filter) {
+ this.filter = filter;
+ try {
+ Files.walkFileTree(combinedPath, this);
+ } catch (IOException e) {
+ throw new InternalError(e);
+ }
+ }
+
+ /**
+ * Compares the glob pattern against the file name.
+ */
+ private void find(Path file) {
+ Path name = file.getFileName();
+ if (name != null && filter.matches(name)) {
+ fileNames.add(file);
+ }
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ find(file);
+ return CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
+ find(dir);
+ return CONTINUE;
+ }
+
+ @Override
+ public Iterator<Path> iterator() {
+ return fileNames.iterator();
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java
new file mode 100644
index 000000000..f60e4270c
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.collect;
+
+public final class SearchFor {
+ private final String name;
+ private final String type;
+
+ public SearchFor(String name) {
+ this(name, "");
+ }
+
+ public SearchFor(String name, String type) {
+ this.name = name;
+ this.type = type;
+ }
+
+ boolean isUnknown() {
+ return "".equals(type);
+ }
+
+ String getType() {
+ return this.type;
+ }
+
+ String getName() {
+ return this.name;
+ }
+
+ @Override
+ public String toString() {
+ return type + ": " + name;
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java
new file mode 100644
index 000000000..559e8f657
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.collect;
+
+import java.nio.file.FileSystem;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SearchPath {
+ private final List<Path> searchPaths = new ArrayList<>();
+ private final FileSupport fileSupport;
+
+ public SearchPath() {
+ this(new FileSupport());
+ }
+
+ public SearchPath(FileSupport fileSupport) {
+ this.fileSupport = fileSupport;
+ }
+
+ public Path find(FileSystem fileSystem, Path entry, String... defaults) {
+ if (isAbsolute(entry)) {
+ if (exists(entry)) {
+ return entry;
+ }
+ return null;
+ }
+
+ if (exists(entry)) {
+ return entry;
+ }
+
+ for (String searchPath : defaults) {
+ Path newPath = fileSystem.getPath(searchPath, entry.toString());
+ if (exists(newPath)) {
+ return newPath;
+ }
+ }
+
+ for (Path searchPath : searchPaths) {
+ Path newPath = fileSystem.getPath(searchPath.toString(), entry.toString());
+ if (exists(newPath)) {
+ return newPath;
+ }
+ }
+
+ return null;
+ }
+
+ private boolean isAbsolute(Path entry) {
+ return fileSupport.isAbsolute(entry);
+ }
+
+ private boolean exists(Path entry) {
+ return fileSupport.exists(entry);
+ }
+
+ public void add(String... paths) {
+ for (String name : paths) {
+ Path path = Paths.get(name);
+ searchPaths.add(path);
+ }
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java
new file mode 100644
index 000000000..f2f6c1bb3
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.collect;
+
+public interface SourceProvider {
+ ClassSource findSource(String name, SearchPath searchPath);
+
+ boolean supports(String type);
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java
new file mode 100644
index 000000000..bf5d34e42
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.collect.classname;
+
+import jdk.tools.jaotc.collect.ClassSource;
+
+import java.util.function.BiConsumer;
+
+public final class ClassNameSource implements ClassSource {
+ private final String name;
+ private final ClassLoader classLoader;
+
+ ClassNameSource(String name, ClassLoader classLoader) {
+ this.name = name;
+ this.classLoader = classLoader;
+ }
+
+ @Override
+ public void eachClass(BiConsumer<String, ClassLoader> consumer) {
+ consumer.accept(name, classLoader);
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java
new file mode 100644
index 000000000..23c731fd3
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.collect.classname;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.SearchPath;
+import jdk.tools.jaotc.collect.SourceProvider;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public final class ClassNameSourceProvider implements SourceProvider {
+ public static final String TYPE = "class";
+ private final ClassLoader classLoader;
+
+ public ClassNameSourceProvider(FileSupport fileSupport) {
+ String classPath = System.getProperty("java.class.path");
+ ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
+ if (classPath != null && !classPath.isEmpty()) {
+ classLoader = systemClassLoader;
+ } else {
+ Path path = Paths.get(".").toAbsolutePath();
+ classLoader = fileSupport.createClassLoader(path, systemClassLoader);
+ }
+ }
+
+ @Override
+ public ClassSource findSource(String name0, SearchPath searchPath) {
+ String name = name0;
+ Path path = Paths.get(name);
+ if (ClassSource.pathIsClassFile(path)) {
+ name = ClassSource.makeClassName(path);
+ }
+ try {
+ classLoader.loadClass(name);
+ return new ClassNameSource(name, classLoader);
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean supports(String type) {
+ return TYPE.equals(type);
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java
new file mode 100644
index 000000000..7df6e24a2
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.collect.directory;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSystemFinder;
+
+import java.nio.file.Path;
+import java.util.function.BiConsumer;
+
+public final class DirectorySource implements ClassSource {
+ private final Path directoryPath;
+ private final ClassLoader classLoader;
+
+ DirectorySource(Path directoryPath, ClassLoader classLoader) {
+ this.directoryPath = directoryPath;
+ this.classLoader = classLoader;
+ }
+
+ @Override
+ public void eachClass(BiConsumer<String, ClassLoader> consumer) {
+ FileSystemFinder finder = new FileSystemFinder(directoryPath, ClassSource::pathIsClassFile);
+
+ for (Path path : finder) {
+ consumer.accept(ClassSource.makeClassName(directoryPath.relativize(path).normalize()), classLoader);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "directory:" + directoryPath.toString();
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java
new file mode 100644
index 000000000..1c7e2b2a5
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.collect.directory;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.SearchPath;
+import jdk.tools.jaotc.collect.SourceProvider;
+
+import java.net.MalformedURLException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+
+public final class DirectorySourceProvider implements SourceProvider {
+ private final FileSupport fileSupport;
+ private final FileSystem fileSystem;
+ public static final String TYPE = "directory";
+
+ public DirectorySourceProvider(FileSupport fileSupport) {
+ this.fileSupport = fileSupport;
+ fileSystem = FileSystems.getDefault();
+ }
+
+ @Override
+ public ClassSource findSource(String name, SearchPath searchPath) {
+ Path directoryPath = fileSystem.getPath(name);
+
+ if (!fileSupport.exists(directoryPath)) {
+ return null;
+ }
+ if (!fileSupport.isDirectory(directoryPath)) {
+ return null;
+ }
+
+ try {
+ ClassLoader classLoader = fileSupport.createClassLoader(directoryPath);
+ return new DirectorySource(directoryPath, classLoader);
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean supports(String type) {
+ return TYPE.equals(type);
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java
new file mode 100644
index 000000000..e86921191
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.collect.jar;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSystemFinder;
+
+import java.nio.file.Path;
+import java.util.function.BiConsumer;
+
+public final class JarFileSource implements ClassSource {
+ private final Path jarFile;
+ private final Path jarRootPath;
+ private final ClassLoader classLoader;
+
+ JarFileSource(Path jarFile, Path jarRootPath, ClassLoader classLoader) {
+ this.jarFile = jarFile;
+ this.jarRootPath = jarRootPath;
+ this.classLoader = classLoader;
+ }
+
+ @Override
+ public void eachClass(BiConsumer<String, ClassLoader> consumer) {
+ FileSystemFinder finder = new FileSystemFinder(jarRootPath, ClassSource::pathIsClassFile);
+
+ for (Path path : finder) {
+ consumer.accept(ClassSource.makeClassName(jarRootPath.relativize(path).normalize()), classLoader);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "jar:" + jarFile.toString();
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java
new file mode 100644
index 000000000..428f3b67e
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.collect.jar;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.SearchPath;
+import jdk.tools.jaotc.collect.SourceProvider;
+
+import java.net.MalformedURLException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.ProviderNotFoundException;
+
+public final class JarSourceProvider implements SourceProvider {
+ private final FileSystem fileSystem;
+ private final FileSupport fileSupport;
+ public static final String TYPE = "jar";
+
+ public JarSourceProvider() {
+ this(new FileSupport());
+ }
+
+ public JarSourceProvider(FileSupport fileSupport) {
+ this.fileSupport = fileSupport;
+ fileSystem = FileSystems.getDefault();
+ }
+
+ @Override
+ public ClassSource findSource(String name, SearchPath searchPath) {
+ Path fileName = fileSystem.getPath(name);
+ Path jarFile = searchPath.find(fileSystem, fileName);
+
+ if (!validPath(jarFile)) {
+ return null;
+ }
+
+ return createSource(jarFile);
+ }
+
+ private ClassSource createSource(Path jarFile) {
+ try {
+ Path jarRootPath = fileSupport.getJarFileSystemRoot(jarFile);
+ if (jarRootPath == null) {
+ return null;
+ }
+ ClassLoader classLoader = fileSupport.createClassLoader(jarFile);
+ return new JarFileSource(jarFile, jarRootPath, classLoader);
+ } catch (ProviderNotFoundException | MalformedURLException e) {
+ }
+ return null;
+ }
+
+ @Override
+ public boolean supports(String type) {
+ return TYPE.equals(type);
+ }
+
+ private boolean validPath(Path jarFile) {
+ return jarFile != null && !fileSupport.isDirectory(jarFile);
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java
new file mode 100644
index 000000000..80975f952
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.collect.module;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSystemFinder;
+
+import java.nio.file.Path;
+import java.util.function.BiConsumer;
+
+public final class ModuleSource implements ClassSource {
+ private final Path modulePath;
+ private final ClassLoader classLoader;
+
+ ModuleSource(Path modulePath, ClassLoader classLoader) {
+ this.modulePath = modulePath;
+ this.classLoader = classLoader;
+ }
+
+ public Path getModulePath() {
+ return modulePath;
+ }
+
+ @Override
+ public void eachClass(BiConsumer<String, ClassLoader> consumer) {
+ FileSystemFinder finder = new FileSystemFinder(modulePath, ClassSource::pathIsClassFile);
+
+ for (Path path : finder) {
+ consumer.accept(ClassSource.makeClassName(modulePath.relativize(path).normalize()), classLoader);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "module:" + modulePath.toString();
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java
new file mode 100644
index 000000000..cea1ba88b
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.collect.module;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.SearchPath;
+import jdk.tools.jaotc.collect.SourceProvider;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+
+public final class ModuleSourceProvider implements SourceProvider {
+ private final FileSystem fileSystem;
+ private final ClassLoader classLoader;
+ private final FileSupport fileSupport;
+ public static final String TYPE = "module";
+
+ public ModuleSourceProvider() {
+ this(FileSystems.getFileSystem(URI.create("jrt:/")), ClassLoader.getSystemClassLoader(), new FileSupport());
+ }
+
+ public ModuleSourceProvider(FileSystem fileSystem, ClassLoader classLoader, FileSupport fileSupport) {
+ this.fileSystem = fileSystem;
+ this.classLoader = classLoader;
+ this.fileSupport = fileSupport;
+ }
+
+ @Override
+ public ClassSource findSource(String name, SearchPath searchPath) {
+ Path path = fileSystem.getPath(name);
+ Path dir = fileSystem.getPath("modules");
+
+ if (dir == null || !fileSupport.isDirectory(dir)) {
+ return null;
+ }
+
+ Path found = findModuleDirectory(dir, path);
+
+ if (found == null) {
+ return null;
+ }
+
+ return new ModuleSource(found, classLoader);
+ }
+
+ private Path findModuleDirectory(Path root, Path path) {
+ try {
+ return fileSupport.getSubDirectory(fileSystem, root, path);
+ } catch (IOException e) {
+ throw new InternalError(e);
+ }
+ }
+
+ @Override
+ public boolean supports(String type) {
+ return TYPE.equals(type);
+ }
+}
diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/NativeOrderOutputStream.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/NativeOrderOutputStream.java
new file mode 100644
index 000000000..e3b7b4a00
--- /dev/null
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/NativeOrderOutputStream.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package jdk.tools.jaotc.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+
+public final class NativeOrderOutputStream {
+ private final PatchableByteOutputStream os = new PatchableByteOutputStream();
+ private final byte[] backingArray = new byte[8];
+ private final ByteBuffer buffer;
+ private final List<Patchable> patches = new ArrayList<>();
+ private int size;
+
+ public NativeOrderOutputStream() {
+ buffer = ByteBuffer.wrap(backingArray);
+ buffer.order(ByteOrder.nativeOrder());
+ }
+
+ public static int alignUp(int value, int alignment) {
+ if (Integer.bitCount(alignment) != 1) {
+ throw new IllegalArgumentException("Must be a power of 2");
+ }
+
+ int aligned = (value + (alignment - 1)) & -alignment;
+
+ if (aligned < value || (aligned & (alignment - 1)) != 0) {
+ throw new RuntimeException("Error aligning: " + value + " -> " + aligned);
+ }
+ return aligned;
+ }
+
+ public NativeOrderOutputStream putLong(long value) {
+ fillLong(value);
+ os.write(backingArray, 0, 8);
+ size += 8;
+ return this;
+ }
+
+ public NativeOrderOutputStream putInt(int value) {
+ fillInt(value);
+ os.write(backingArray, 0, 4);
+ size += 4;
+ return this;
+ }
+
+ public NativeOrderOutputStream align(int alignment) {
+ int aligned = alignUp(position(), alignment);
+
+ int diff = aligned - position();
+ if (diff > 0) {
+ byte[] b = new byte[diff];
+ os.write(b, 0, b.length);
+ size += diff;
+ }
+
+ assert aligned == position();
+ return this;
+ }
+
+ public int position() {
+ return os.size();
+ }
+
+ private void fillInt(int value) {
+ buffer.putInt(0, value);
+ }
+
+ private void fillLong(long value) {
+ buffer.putLong(0, value);
+ }
+
+ private NativeOrderOutputStream putAt(byte[] data, int length, int position) {
+ os.writeAt(data, length, position);
+ return this;
+ }
+
+ public NativeOrderOutputStream put(byte[] data) {
+ os.write(data, 0, data.length);
+ size += data.length;
+ return this;
+ }
+
+ public byte[] array() {
+ checkPatches();
+ byte[] bytes = os.toByteArray();
+ assert size == bytes.length;
+ return bytes;
+ }
+
+ private void checkPatches() {
+ for (Patchable patch : patches) {
+ if (!patch.patched()) {
+ throw new RuntimeException("Not all patches patched, missing at offset: " + patch);
+ }
+ }
+ }
+
+ public PatchableInt patchableInt() {
+ int position = os.size();
+ PatchableInt patchableInt = new PatchableInt(position);
+ putInt(0);
+ patches.add(patchableInt);
+ return patchableInt;
+ }
+
+ public abstract class Patchable {
+ private final int position;
+ private boolean patched = false;
+
+ Patchable(int position) {
+ this.position = position;
+ }
+
+ protected boolean patched() {
+ return patched;
+ }
+
+ protected void patch(int length) {
+ putAt(backingArray, length, position);
+ patched = true;
+ }
+
+ public int position() {
+ return position;
+ }
+ }
+
+ public class PatchableInt extends Patchable {
+ private int value = 0;
+
+ public PatchableInt(int position) {
+ super(position);
+ }
+
+ public void set(int value) {
+ this.value = value;
+ fillInt(value);
+ patch(4);
+ }
+
+ public int value() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("PatchableInt{");
+ sb.append("position=").append(super.position()).append(", ");
+ sb.append("patched=").append(patched()).append(", ");
+ sb.append("value=").append(value);
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+
+ private static class PatchableByteOutputStream extends ByteArrayOutputStream {
+
+ public void writeAt(byte[] data, int length, int position) {
+ long end = (long) position + (long) length;
+ if (buf.length < end) {
+ throw new IllegalArgumentException("Array not properly sized");
+ }
+ System.arraycopy(data, 0, buf, position, length);
+ }
+ }
+}
diff --git a/src/jdk.aot/share/classes/module-info.java b/src/jdk.aot/share/classes/module-info.java
new file mode 100644
index 000000000..f6341b8ae
--- /dev/null
+++ b/src/jdk.aot/share/classes/module-info.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Defines the Ahead-of-Time (AOT) compiler, <em>{@index jaotc jaotc tool}</em>,
+ * for compiling Java classes into AOT library.
+ *
+ * @moduleGraph
+ * @since 9
+ */
+module jdk.aot {
+ requires jdk.internal.vm.ci;
+ requires jdk.internal.vm.compiler;
+ requires jdk.management;
+}
diff --git a/src/jdk.aot/share/man/jaotc.1 b/src/jdk.aot/share/man/jaotc.1
new file mode 100644
index 000000000..2b25c005a
--- /dev/null
+++ b/src/jdk.aot/share/man/jaotc.1
@@ -0,0 +1,209 @@
+.\" Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
+.\" DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+.\"
+.\" This code is free software; you can redistribute it and/or modify it
+.\" under the terms of the GNU General Public License version 2 only, as
+.\" published by the Free Software Foundation.
+.\"
+.\" This code is distributed in the hope that it will be useful, but WITHOUT
+.\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+.\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+.\" version 2 for more details (a copy is included in the LICENSE file that
+.\" accompanied this code).
+.\"
+.\" You should have received a copy of the GNU General Public License version
+.\" 2 along with this work; if not, write to the Free Software Foundation,
+.\" Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+.\"
+.\" Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+.\" or visit www.oracle.com if you need additional information or have any
+.\" questions.
+.\"
+.\" Automatically generated by Pandoc 2.3.1
+.\"
+.TH "JAOTC" "1" "2020" "JDK 16" "JDK Commands"
+.hy
+.SH NAME
+.PP
+jaotc \- The Java static compiler that produces native code for compiled
+Java methods
+.SH SYNOPSIS
+.PP
+\f[CB]jaotc\f[R] [\f[I]options\f[R]] [\f[I]name\f[R] | \f[I]list\f[R]]
+.TP
+.B \f[I]options\f[R]
+Command\-line options separated by spaces.
+See \f[B]jaotc Options\f[R].
+.RS
+.RE
+.TP
+.B \f[I]name\f[R]
+The Java class or jar file from which Java methods will be compiled.
+.RS
+.RE
+.TP
+.B \f[I]list\f[R]
+Colon (\f[CB]:\f[R]) separated list of class names, modules, jar files or
+directories which contain class files.
+.RS
+.RE
+.SH DESCRIPTION
+.PP
+The \f[CB]jaotc\f[R] command is a Java Ahead\-Of\-Time (AOT) static
+compiler which produces native code in the form of a shared library for
+the Java methods in specified Java class files.
+The Java Virtual Machine can load these AOT libraries and use native
+code from them when corresponding Java methods are called.
+By using \f[CB]jaotc\f[R], there is no need to wait for the JIT compiler
+to generate (by compiling bytecode) the fast native code for these Java
+methods.
+The code is already generated by \f[CB]jaotc\f[R] and ready to be
+immediately used.
+For the same reason, there is no need to execute these methods in the
+Interpreter because fast compiled native code can be executed instead.
+.PP
+\f[B]Note:\f[R]
+.PP
+The \f[CB]jaotc\f[R] command is experimental.
+See \f[B]JEP 295: Ahead\-of\-Time Compilation\f[R]
+[https://openjdk.java.net/jeps/295] for complete details.
+.SH JAOTC OPTIONS
+.TP
+.B \f[CB]\-\-output\f[R] \f[I]file\f[R]
+Output file name.
+Default name is "unnamed.so".
+.RS
+.RE
+.TP
+.B \f[CB]\-\-class\-name\f[R] \f[I]class\-names\f[R]
+List of Java classes to compile.
+.RS
+.RE
+.TP
+.B \f[CB]\-\-jar\f[R] \f[I]jar\-files\f[R]
+List of JAR files to compile.
+.RS
+.RE
+.TP
+.B \f[CB]\-\-module\f[R] \f[I]modules\f[R]
+List of Java modules to compile.
+.RS
+.RE
+.TP
+.B \f[CB]\-\-directory\f[R] \f[I]dirs\f[R]
+List of directories to search for files to compile.
+.RS
+.RE
+.TP
+.B \f[CB]\-\-search\-path\f[R] \f[I]dirs\f[R]
+List of directories to search for specified files.
+.RS
+.RE
+.TP
+.B \f[CB]\-\-compile\-commands\f[R] \f[I]file\f[R]
+Name of the file containing the compile commands:
+.RS
+.TP
+.B \f[CB]exclude\f[R]
+Excludes compilation of specified methods.
+.RS
+.RE
+.TP
+.B \f[CB]compileOnly\f[R]
+Compiles only specified methods.
+.RS
+.RE
+.PP
+Regular expressions are used to specify classes and methods.
+For example:
+.IP
+.nf
+\f[CB]
+exclude\ sun.util.resources..*.TimeZoneNames_.*.getContents\\(\\)\\[\\[Ljava/lang/Object;\
+exclude\ sun.security.ssl.*\
+compileOnly\ java.lang.String.*
+\f[R]
+.fi
+.RE
+.TP
+.B \f[CB]\-\-compile\-for\-tiered\f[R]
+Generates profiling code for tiered compilation.
+By default, profiling code is not generated (could be changed in a
+future).
+.RS
+.RE
+.TP
+.B \f[CB]\-\-compile\-with\-assertions\f[R]
+Generates code with java assertions.
+By default, assertions code is not generated.
+.RS
+.RE
+.TP
+.B \f[CB]\-\-compile\-threads\f[R] \f[I]number\f[R]
+Sets the number of compilation threads used.
+The default value is \f[CB]min(16,\ available_cpus)\f[R].
+.RS
+.RE
+.TP
+.B \f[CB]\-\-ignore\-errors\f[R]
+Ignores all exceptions thrown during class loading.
+By default, the tool will exit compilation if class loading throws an
+exception.
+.RS
+.RE
+.TP
+.B \f[CB]\-\-exit\-on\-error\f[R]
+Exits on compilation errors.
+By default, failed compilation is skipped and compilation of other
+methods continues.
+.RS
+.RE
+.TP
+.B \f[CB]\-\-info\f[R]
+Prints information about compilation phases.
+.RS
+.RE
+.TP
+.B \f[CB]\-\-verbose\f[R]
+Prints more details about compilation phases.
+.RS
+.RE
+.TP
+.B \f[CB]\-\-debug\f[R]
+Prints comprehensive details.
+.RS
+.RE
+.TP
+.B \f[CB]\-\-help\f[R] or \f[CB]\-h\f[R] or \f[CB]\-?\f[R]
+Prints a summary of standard options and exits the tool.
+.RS
+.RE
+.TP
+.B \f[CB]\-\-version\f[R]
+Prints version information.
+.RS
+.RE
+.TP
+.B \f[CB]\-J\f[R]\f[I]flag\f[R]
+Provides a flag to pass to the runtime system.
+To pass more than one flag, provide an instance of this option for each
+flag or flag argument needed.
+.RS
+.RE
+.SH JAOTC EXAMPLES
+.PP
+Use the \f[CB]jaotc\f[R] tool to execute AOT compilation.
+.IP
+.nf
+\f[CB]
+jaotc\ \-\-output\ libHelloWorld.so\ HelloWorld.class
+\f[R]
+.fi
+.PP
+Specify a generated AOT library during application execution:
+.IP
+.nf
+\f[CB]
+java\ \-XX:+UnlockExperimentalVMOptions\ \-XX:AOTLibrary=./libHelloWorld.so\ HelloWorld
+\f[R]
+.fi
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java
index d2f8db5ef..323c2a2d4 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -133,6 +133,8 @@ public class CodeBlob extends VMObject {
// Typing
public boolean isBufferBlob() { return false; }
+ public boolean isAOT() { return false; }
+
public boolean isCompiled() { return false; }
public boolean isNMethod() { return false; }
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
index 079f7b6c8..f2e998c56 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -74,6 +74,7 @@ public class InstanceKlass extends Klass {
private static int MISC_HAS_NONSTATIC_CONCRETE_METHODS;
private static int MISC_DECLARES_NONSTATIC_CONCRETE_METHODS;
private static int MISC_HAS_BEEN_REDEFINED;
+ private static int MISC_HAS_PASSED_FINGERPRINT_CHECK;
private static int MISC_IS_SCRATCH_CLASS;
private static int MISC_IS_SHARED_BOOT_CLASS;
private static int MISC_IS_SHARED_PLATFORM_CLASS;
@@ -131,6 +132,7 @@ public class InstanceKlass extends Klass {
MISC_HAS_NONSTATIC_CONCRETE_METHODS = db.lookupIntConstant("InstanceKlass::_misc_has_nonstatic_concrete_methods").intValue();
MISC_DECLARES_NONSTATIC_CONCRETE_METHODS = db.lookupIntConstant("InstanceKlass::_misc_declares_nonstatic_concrete_methods").intValue();
MISC_HAS_BEEN_REDEFINED = db.lookupIntConstant("InstanceKlass::_misc_has_been_redefined").intValue();
+ MISC_HAS_PASSED_FINGERPRINT_CHECK = db.lookupIntConstant("InstanceKlass::_misc_has_passed_fingerprint_check").intValue();
MISC_IS_SCRATCH_CLASS = db.lookupIntConstant("InstanceKlass::_misc_is_scratch_class").intValue();
MISC_IS_SHARED_BOOT_CLASS = db.lookupIntConstant("InstanceKlass::_misc_is_shared_boot_class").intValue();
MISC_IS_SHARED_PLATFORM_CLASS = db.lookupIntConstant("InstanceKlass::_misc_is_shared_platform_class").intValue();
@@ -281,6 +283,11 @@ public class InstanceKlass extends Klass {
if (isInterface()) {
size += wordLength;
}
+
+ if (hasStoredFingerprint()) {
+ size += 8; // uint64_t
+ }
+
return alignSize(size);
}
@@ -288,6 +295,26 @@ public class InstanceKlass extends Klass {
return (int) miscFlags.getValue(this);
}
+ public static boolean shouldStoreFingerprint() {
+ VM vm = VM.getVM();
+ if (vm.getCommandLineBooleanFlag("EnableJVMCI") && !vm.getCommandLineBooleanFlag("UseJVMCICompiler")) {
+ return true;
+ }
+ if (vm.getCommandLineBooleanFlag("DumpSharedSpaces")) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean hasStoredFingerprint() {
+ // has_stored_fingerprint() @ instanceKlass.cpp can return true only if INCLUDE_AOT is
+ // set during compilation.
+ if (!VM.getVM().hasAOT()) {
+ return false;
+ }
+ return shouldStoreFingerprint() || isShared();
+ }
+
public static long getHeaderSize() { return headerSize; }
public short getFieldAccessFlags(int index) {
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java
index f3cbacbbd..b42feec3f 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -89,6 +89,8 @@ public class VM {
private FileMapInfo fileMapInfo;
private Bytes bytes;
+ /** Flag indicating if AOT is enabled in the build */
+ private boolean hasAOT;
/** Flag indicating if JVMTI support is included in the build */
private boolean isJvmtiSupported;
/** Flags indicating whether we are attached to a core, C1, or C2 build */
@@ -444,6 +446,16 @@ public class VM {
invocationEntryBCI = db.lookupIntConstant("InvocationEntryBci").intValue();
+ // We infer AOT if _method @ methodCounters is declared.
+ {
+ Type type = db.lookupType("MethodCounters");
+ if (type.getField("_method", false, false) == null) {
+ hasAOT = false;
+ } else {
+ hasAOT = true;
+ }
+ }
+
// We infer the presence of JVMTI from the presence of the InstanceKlass::_breakpoints field.
{
Type type = db.lookupType("InstanceKlass");
@@ -827,6 +839,11 @@ public class VM {
return isBigEndian;
}
+ /** Returns true if AOT is enabled, false otherwise */
+ public boolean hasAOT() {
+ return hasAOT;
+ }
+
/** Returns true if JVMTI is supported, false otherwise */
public boolean isJvmtiSupported() {
return isJvmtiSupported;
diff --git a/src/jdk.internal.vm.compiler/share/classes/module-info.java b/src/jdk.internal.vm.compiler/share/classes/module-info.java
index 100dde9ec..fe3bcc93d 100644
--- a/src/jdk.internal.vm.compiler/share/classes/module-info.java
+++ b/src/jdk.internal.vm.compiler/share/classes/module-info.java
@@ -43,15 +43,46 @@ module jdk.internal.vm.compiler {
uses org.graalvm.compiler.serviceprovider.JMXService;
exports jdk.internal.vm.compiler.collections to jdk.internal.vm.compiler.management;
+ exports org.graalvm.compiler.api.directives to jdk.aot;
+ exports org.graalvm.compiler.api.runtime to jdk.aot;
+ exports org.graalvm.compiler.api.replacements to jdk.aot;
+ exports org.graalvm.compiler.asm.amd64 to jdk.aot;
+ exports org.graalvm.compiler.asm.aarch64 to jdk.aot;
+ exports org.graalvm.compiler.bytecode to jdk.aot;
+ exports org.graalvm.compiler.code to jdk.aot;
+ exports org.graalvm.compiler.core to jdk.aot;
exports org.graalvm.compiler.core.common to
+ jdk.aot,
jdk.internal.vm.compiler.management;
+ exports org.graalvm.compiler.core.target to jdk.aot;
exports org.graalvm.compiler.debug to
+ jdk.aot,
jdk.internal.vm.compiler.management;
+ exports org.graalvm.compiler.graph to jdk.aot;
exports org.graalvm.compiler.hotspot to
+ jdk.aot,
jdk.internal.vm.compiler.management;
+ exports org.graalvm.compiler.hotspot.meta to jdk.aot;
+ exports org.graalvm.compiler.hotspot.replacements to jdk.aot;
+ exports org.graalvm.compiler.hotspot.stubs to jdk.aot;
+ exports org.graalvm.compiler.hotspot.word to jdk.aot;
+ exports org.graalvm.compiler.java to jdk.aot;
+ exports org.graalvm.compiler.lir.asm to jdk.aot;
+ exports org.graalvm.compiler.lir.phases to jdk.aot;
+ exports org.graalvm.compiler.nodes to jdk.aot;
+ exports org.graalvm.compiler.nodes.graphbuilderconf to jdk.aot;
exports org.graalvm.compiler.options to
+ jdk.aot,
jdk.internal.vm.compiler.management;
+ exports org.graalvm.compiler.phases to jdk.aot;
exports org.graalvm.compiler.phases.common.jmx to jdk.internal.vm.compiler.management;
+ exports org.graalvm.compiler.phases.tiers to jdk.aot;
+ exports org.graalvm.compiler.printer to jdk.aot;
+ exports org.graalvm.compiler.runtime to jdk.aot;
+ exports org.graalvm.compiler.replacements to jdk.aot;
exports org.graalvm.compiler.serviceprovider to
+ jdk.aot,
jdk.internal.vm.compiler.management;
+ exports org.graalvm.compiler.word to jdk.aot;
+ exports jdk.internal.vm.compiler.word to jdk.aot;
}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java
index 235104ad3..976ce455d 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java
@@ -112,6 +112,7 @@ import jdk.vm.ci.meta.Value;
* global invariants such as using {@link Object#equals(Object)} to compare certain types instead of
* identity comparisons.
*/
+@AddExports("jdk.internal.vm.ci/*=jdk.aot")
public class CheckGraalInvariants extends GraalCompilerTest {
/**
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifySystemPropertyUsage.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifySystemPropertyUsage.java
index 226d5f7fa..29c12ab0d 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifySystemPropertyUsage.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifySystemPropertyUsage.java
@@ -101,6 +101,10 @@ public class VerifySystemPropertyUsage extends VerifyPhase<CoreProviders> {
// * its JDK substitutions to mimic required JDK semantics
// * native-image for config info
return;
+ } else if (packageName.startsWith("jdk.tools.jaotc")) {
+ // Workaround since jdk.internal.vm.ci/jdk.vm.ci.services is not exported to jdk.aot.
+ // The jaotc launcher dynamically adds these exports.
+ return;
}
for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.TYPE)) {
ResolvedJavaMethod callee = t.targetMethod();
diff --git a/test/hotspot/jtreg/ProblemList-aot.txt b/test/hotspot/jtreg/ProblemList-aot.txt
new file mode 100644
index 000000000..a42887547
--- /dev/null
+++ b/test/hotspot/jtreg/ProblemList-aot.txt
@@ -0,0 +1,82 @@
+#
+# Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+#############################################################################
+#
+# List of quarantined tests for testing with AOT.
+#
+#############################################################################
+
+serviceability/sa/CDSJMapClstats.java 8216181 generic-all
+serviceability/sa/ClhsdbAttach.java 8216181 generic-all
+serviceability/sa/ClhsdbCDSCore.java 8216181 generic-all
+serviceability/sa/ClhsdbCDSJstackPrintAll.java 8216181 generic-all
+serviceability/sa/ClhsdbField.java 8216181 generic-all
+serviceability/sa/ClhsdbFindPC.java#id0 8216181 generic-all
+serviceability/sa/ClhsdbFindPC.java#id1 8216181 generic-all
+serviceability/sa/ClhsdbFlags.java 8216181 generic-all
+serviceability/sa/ClhsdbInspect.java 8216181 generic-all
+serviceability/sa/ClhsdbJdis.java 8216181 generic-all
+serviceability/sa/ClhsdbJhisto.java 8216181 generic-all
+serviceability/sa/ClhsdbJstack.java#id0 8216181 generic-all
+serviceability/sa/ClhsdbJstack.java#id1 8216181 generic-all
+serviceability/sa/ClhsdbJstackXcompStress.java 8216181 generic-all
+serviceability/sa/ClhsdbLongConstant.java 8216181 generic-all
+serviceability/sa/ClhsdbPmap.java 8216181 generic-all
+serviceability/sa/ClhsdbPrintAll.java 8216181 generic-all
+serviceability/sa/ClhsdbPrintAs.java 8216181 generic-all
+serviceability/sa/ClhsdbPrintStatics.java 8216181 generic-all
+serviceability/sa/ClhsdbPstack.java 8216181 generic-all
+serviceability/sa/ClhsdbRegionDetailsScanOopsForG1.java 8216181 generic-all
+serviceability/sa/ClhsdbScanOops.java#id0 8216181 generic-all
+serviceability/sa/ClhsdbScanOops.java#id1 8216181 generic-all
+serviceability/sa/ClhsdbSource.java 8216181 generic-all
+serviceability/sa/ClhsdbThread.java 8216181 generic-all
+serviceability/sa/ClhsdbVmStructsDump.java 8216181 generic-all
+serviceability/sa/ClhsdbWhere.java 8216181 generic-all
+serviceability/sa/DeadlockDetectionTest.java 8216181 generic-all
+serviceability/sa/JhsdbThreadInfoTest.java 8216181 generic-all
+serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java 8216181 generic-all
+serviceability/sa/sadebugd/DebugdConnectTest.java 8216181 generic-all
+serviceability/sa/sadebugd/SADebugDTest.java 8216181 generic-all
+serviceability/sa/TestClassDump.java 8216181 generic-all
+serviceability/sa/TestClhsdbJstackLock.java 8216181 generic-all
+serviceability/sa/TestCpoolForInvokeDynamic.java 8216181 generic-all
+serviceability/sa/TestDefaultMethods.java 8216181 generic-all
+serviceability/sa/TestG1HeapRegion.java 8216181 generic-all
+serviceability/sa/TestHeapDumpForInvokeDynamic.java 8216181 generic-all
+serviceability/sa/TestHeapDumpForLargeArray.java 8216181 generic-all
+serviceability/sa/TestInstanceKlassSizeForInterface.java 8216181 generic-all
+serviceability/sa/TestInstanceKlassSize.java 8216181 generic-all
+serviceability/sa/TestIntConstant.java 8216181 generic-all
+serviceability/sa/TestJhsdbJstackLock.java 8216181 generic-all
+serviceability/sa/TestJhsdbJstackMixed.java 8216181 generic-all
+serviceability/sa/TestJmapCore.java 8216181 generic-all
+serviceability/sa/TestJmapCoreMetaspace.java 8216181 generic-all
+serviceability/sa/TestPrintMdo.java 8216181 generic-all
+serviceability/sa/TestRevPtrsForInvokeDynamic.java 8216181 generic-all
+serviceability/sa/TestType.java 8216181 generic-all
+serviceability/sa/TestUniverse.java 8216181 generic-all
+
+vmTestbase/vm/mlvm/indy/stress/java/relinkMutableCallSiteFreq/Test.java 8226689 generic-all
+vmTestbase/vm/mlvm/indy/stress/java/relinkVolatileCallSiteFreq/Test.java 8226689 generic-all
diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT
index f6e6209cd..e350faa40 100644
--- a/test/hotspot/jtreg/TEST.ROOT
+++ b/test/hotspot/jtreg/TEST.ROOT
@@ -67,6 +67,8 @@ requires.properties= \
vm.hasDTrace \
vm.rtm.cpu \
vm.rtm.compiler \
+ vm.aot \
+ vm.aot.enabled \
vm.cds \
vm.cds.custom.loaders \
vm.cds.write.archived.java.heap \
diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups
index 915dac962..5a3765365 100644
--- a/test/hotspot/jtreg/TEST.groups
+++ b/test/hotspot/jtreg/TEST.groups
@@ -45,7 +45,7 @@ hotspot_compiler_xcomp = \
hotspot_compiler_all_gcs = \
:hotspot_compiler \
- -compiler/jvmci \
+ -:tier1_compiler_aot_jvmci \
-compiler/graalunit
hotspot_gc = \
@@ -242,8 +242,13 @@ tier3_compiler = \
-:tier2_compiler
tier1_compiler_not_xcomp = \
+ compiler/aot \
compiler/profiling
+tier1_compiler_aot_jvmci = \
+ compiler/aot \
+ compiler/jvmci
+
tier1_compiler_graal = \
compiler/graalunit/HotspotTest.java
diff --git a/test/hotspot/jtreg/applications/ctw/modules/jdk_aot.java b/test/hotspot/jtreg/applications/ctw/modules/jdk_aot.java
new file mode 100644
index 000000000..b2d6d77b6
--- /dev/null
+++ b/test/hotspot/jtreg/applications/ctw/modules/jdk_aot.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary run CTW for all classes from jdk.aot module
+ *
+ * @library /test/lib / /testlibrary/ctw/src
+ * @modules java.base/jdk.internal.access
+ * java.base/jdk.internal.jimage
+ * java.base/jdk.internal.misc
+ * java.base/jdk.internal.reflect
+ * @modules jdk.aot
+ *
+ * @build jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver/timeout=7200 sun.hotspot.tools.ctw.CtwRunner modules:jdk.aot
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/AotCompiler.java b/test/hotspot/jtreg/compiler/aot/AotCompiler.java
new file mode 100644
index 000000000..8ad1da403
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/AotCompiler.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot;
+
+import jdk.test.lib.Platform;
+import jdk.test.lib.artifacts.Artifact;
+import jdk.test.lib.artifacts.ArtifactResolver;
+import jdk.test.lib.artifacts.ArtifactResolverException;
+import jdk.test.lib.process.OutputAnalyzer;
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import jdk.test.lib.JDKToolLauncher;
+import jdk.test.lib.Utils;
+import jdk.test.lib.process.ProcessTools;
+
+/**
+ * A simple class calling AOT compiler over requested items
+ */
+public class AotCompiler {
+
+ private final static String METHODS_LIST_FILENAME = "methodsList.txt";
+
+ public static void main(String args[]) {
+ String className = null;
+ List<String> compileList = new ArrayList<>();
+ String libName = null;
+ List<String> extraopts = new ArrayList<>();
+ for (int i = 0; i < args.length; i++) {
+ switch (args[i]) {
+ case "-class":
+ className = args[++i];
+ break;
+ case "-compile":
+ compileList.add("compileOnly " + args[++i]);
+ break;
+ case "-libname":
+ libName = args[++i];
+ break;
+ case "-extraopt":
+ extraopts.add(args[++i]);
+ break;
+ default:
+ throw new Error("Unknown option: " + args[i]);
+ }
+ }
+ extraopts.add("-classpath");
+ extraopts.add(Utils.TEST_CLASS_PATH + File.pathSeparator + Utils.TEST_SRC);
+ if (className != null && libName != null) {
+ OutputAnalyzer oa = launchCompiler(libName, className, extraopts, compileList);
+ oa.shouldHaveExitValue(0);
+ } else {
+ printUsage();
+ throw new Error("Mandatory arguments aren't passed");
+ }
+ }
+
+ public static OutputAnalyzer launchCompilerSimple(String... args) {
+ return launchJaotc(Arrays.asList(args), null);
+ }
+
+ public static OutputAnalyzer launchCompiler(String libName, String item, List<String> extraopts,
+ List<String> compList) {
+ Path file = null;
+ if (compList != null && !compList.isEmpty()) {
+ file = Paths.get(METHODS_LIST_FILENAME);
+ try {
+ Files.write(file, compList, StandardOpenOption.CREATE);
+ } catch (IOException e) {
+ throw new Error("Couldn't write " + METHODS_LIST_FILENAME + " " + e, e);
+ }
+ }
+ List<String> args = new ArrayList<>();
+ args.add("--compile-with-assertions");
+ args.add("--info");
+ args.add("--output");
+ args.add(libName);
+ if (file != null) {
+ args.add("--compile-commands");
+ args.add(file.toString());
+ }
+ args.add("--class-name");
+ args.add(item);
+ String linker = resolveLinker();
+ if (linker != null) {
+ args.add("--linker-path");
+ args.add(linker);
+ }
+ // Execute with asserts
+ args.add("-J-ea");
+ args.add("-J-esa");
+ // we don't want to run jaotc w/ Xcomp even if it's in extraopts
+ args.add("-J-Xmixed");
+ return launchJaotc(args, extraopts);
+ }
+
+ private static OutputAnalyzer launchJaotc(List<String> args, List<String> extraVmOpts) {
+ JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jaotc");
+ for (String vmOpt : Utils.getTestJavaOpts()) {
+ launcher.addVMArg(vmOpt);
+ }
+ if (extraVmOpts != null) {
+ for (String vmOpt : extraVmOpts) {
+ launcher.addVMArg(vmOpt);
+ }
+ }
+ for (String arg : args) {
+ launcher.addToolArg(arg);
+ }
+ try {
+ return ProcessTools.executeCommand(new ProcessBuilder(launcher.getCommand()).redirectErrorStream(true));
+ } catch (Throwable e) {
+ throw new Error("Can't start test process: " + e, e);
+ }
+ }
+
+ public static void printUsage() {
+ System.err.println("Usage: " + AotCompiler.class.getName()
+ + " -class <class> -libname <.so name>"
+ + " [-compile <compileItems>]* [-extraopt <java option>]*");
+ }
+
+ // runs ld -v and check its exit code
+ private static boolean checkLd(Path bin) {
+ try {
+ return 0 == ProcessTools.executeCommand(bin.toString(), "-v")
+ .getExitValue();
+ } catch (Throwable t) {
+ // any errors mean ld doesn't work
+ return false;
+ }
+ }
+
+ public static String resolveLinker() {
+ Path linker = null;
+ // if non windows, 1st, check if PATH has ld
+ if (!Platform.isWindows()) {
+ String bin = "ld";
+ for (String path : System.getenv("PATH").split(File.pathSeparator)) {
+ Path ld = Paths.get(path).resolve("ld");
+ if (Files.exists(ld)) {
+ // there is ld in PATH
+ if (checkLd(ld)) {
+ System.out.println("found working linker: " + ld);
+ // ld works, jaotc is supposed to find and use it
+ return null;
+ } else {
+ System.out.println("found broken linker: " + ld);
+ // ld exists in PATH, but doesn't work, have to use devkit
+ break;
+ }
+ }
+ }
+ }
+ // there is no ld in PATH, will use ld from devkit
+ // artifacts are got from common/conf/jib-profiles.js
+ try {
+ if (Platform.isWindows()) {
+ if (Platform.isX64()) {
+ @Artifact(organization = "jpg.infra.builddeps",
+ name = "devkit-windows_x64",
+ revision = "VS2017-15.5.5+1.0",
+ extension = "tar.gz")
+ class DevkitWindowsX64 { }
+ String artifactName = "jpg.infra.builddeps."
+ + "devkit-windows_x64-"
+ + "VS2017-15.5.5+1.0";
+ Path devkit = ArtifactResolver.resolve(DevkitWindowsX64.class)
+ .get(artifactName);
+ linker = devkit.resolve("VC")
+ .resolve("bin")
+ .resolve("x64")
+ .resolve("link.exe");
+ }
+ } else if (Platform.isOSX()) {
+ @Artifact(organization = "jpg.infra.builddeps",
+ name = "devkit-macosx_x64",
+ revision = "Xcode6.3-MacOSX10.9+1.0",
+ extension = "tar.gz")
+ class DevkitMacosx { }
+ String artifactName = "jpg.infra.builddeps."
+ + "devkit-macosx_x64-"
+ + "Xcode6.3-MacOSX10.9+1.0";
+ Path devkit = ArtifactResolver.resolve(DevkitMacosx.class)
+ .get(artifactName);
+ linker = devkit.resolve("Xcode.app")
+ .resolve("Contents")
+ .resolve("Developer")
+ .resolve("Toolchains")
+ .resolve("XcodeDefault.xctoolchain")
+ .resolve("usr")
+ .resolve("bin")
+ .resolve("ld");
+ } else if (Platform.isLinux()) {
+ if (Platform.isAArch64()) {
+ @Artifact(organization = "jpg.infra.builddeps",
+ name = "devkit-linux_aarch64",
+ revision = "gcc-linaro-aarch64-linux-gnu-4.8-2013.11_linux+1.0",
+ extension = "tar.gz")
+ class DevkitLinuxAArch64 { }
+
+ String artifactName = "jpg.infra.builddeps."
+ + "devkit-linux_aarch64-"
+ + "gcc-linaro-aarch64-linux-gnu-4.8-2013.11_linux+1.0";
+ Path devkit = ArtifactResolver.resolve(DevkitLinuxAArch64.class)
+ .get(artifactName);
+ linker = devkit.resolve("aarch64-linux-gnu")
+ .resolve("bin")
+ .resolve("ld");
+ } else if (Platform.isARM()) {
+ @Artifact(organization = "jpg.infra.builddeps",
+ name = "devkit-linux_arm",
+ revision = "gcc-linaro-arm-linux-gnueabihf-raspbian-2012.09-20120921_linux+1.0",
+ extension = "tar.gz")
+ class DevkitLinuxARM { }
+
+ String artifactName = "jpg.infra.builddeps."
+ + "devkit-linux_arm-"
+ + "gcc-linaro-arm-linux-gnueabihf-raspbian-2012.09-20120921_linux+1.0";
+ Path devkit = ArtifactResolver.resolve(DevkitLinuxARM.class)
+ .get(artifactName);
+ linker = devkit.resolve("arm-linux-gnueabihf")
+ .resolve("bin")
+ .resolve("ld");
+ } else if (Platform.isX64()) {
+ @Artifact(organization = "jpg.infra.builddeps",
+ name = "devkit-linux_x64",
+ revision = "gcc7.3.0-OEL6.4+1.0",
+ extension = "tar.gz")
+ class DevkitLinuxX64 { }
+
+ String artifactName = "jpg.infra.builddeps."
+ + "devkit-linux_x64-"
+ + "gcc7.3.0-OEL6.4+1.0";
+ Path devkit = ArtifactResolver.resolve(DevkitLinuxX64.class)
+ .get(artifactName);
+ linker = devkit.resolve("bin")
+ .resolve("ld");
+ }
+ }
+ } catch (ArtifactResolverException e) {
+ System.err.println("artifact resolution error: " + e);
+ e.printStackTrace(System.err);
+ // let jaotc try to find linker
+ return null;
+ }
+ if (linker != null) {
+ return linker.toAbsolutePath().toString();
+ }
+ return null;
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/DeoptimizationTest.java b/test/hotspot/jtreg/compiler/aot/DeoptimizationTest.java
new file mode 100644
index 000000000..e4752e5cd
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/DeoptimizationTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.DeoptimizationTest
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname libDeoptimizationTest.so
+ * -class compiler.aot.DeoptimizationTest
+ * -compile compiler.aot.DeoptimizationTest.testMethod()D
+ * -extraopt -XX:-UseCompressedOops
+ * @run main/othervm -Xmixed -XX:+UnlockExperimentalVMOptions -XX:+UseAOT -XX:+TieredCompilation
+ * -XX:-UseCompressedOops
+ * -XX:CompileCommand=dontinline,compiler.aot.DeoptimizationTest::*
+ * -XX:AOTLibrary=./libDeoptimizationTest.so -Xbootclasspath/a:.
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * compiler.aot.DeoptimizationTest
+ * @summary check if aot code can be deoptimized
+ */
+
+package compiler.aot;
+
+import java.lang.reflect.Method;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.Utils;
+import jdk.test.whitebox.WhiteBox;
+import compiler.whitebox.CompilerWhiteBoxTest;
+
+public final class DeoptimizationTest {
+ private static final String TEST_METHOD = "testMethod";
+ private static final WhiteBox WB = WhiteBox.getWhiteBox();
+ private final Method testMethod;
+
+ private DeoptimizationTest() {
+ try {
+ testMethod = getClass().getDeclaredMethod(TEST_METHOD);
+ } catch (NoSuchMethodException e) {
+ throw new Error("TEST BUG: no test method found", e);
+ }
+ }
+
+ public static void main(String args[]) {
+ new DeoptimizationTest().test();
+ }
+
+ private double testMethod() {
+ return 42 / 0;
+ }
+
+ private void test() {
+ Asserts.assertTrue(WB.isMethodCompiled(testMethod),
+ "Method expected to be compiled");
+ Asserts.assertEQ(WB.getMethodCompilationLevel(testMethod),
+ CompilerWhiteBoxTest.COMP_LEVEL_AOT,
+ "Unexpected compilation level at start");
+ Utils.runAndCheckException(() -> testMethod(), ArithmeticException.class);
+ Asserts.assertFalse(WB.isMethodCompiled(testMethod),
+ "Method is unexpectedly compiled after deoptimization");
+ Asserts.assertEQ(WB.getMethodCompilationLevel(testMethod), 0,
+ "Unexpected compilation level after deoptimization");
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/HelloWorldPrinter.java b/test/hotspot/jtreg/compiler/aot/HelloWorldPrinter.java
new file mode 100644
index 000000000..e91a53e2f
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/HelloWorldPrinter.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot;
+
+public class HelloWorldPrinter {
+ public static final String MESSAGE = "Hello world";
+ public static final String CLINIT_MESSAGE = "Hello <clinit> world";
+
+ static {
+ System.out.println(CLINIT_MESSAGE);
+ }
+
+ public static void main(String args[]) {
+ print();
+ }
+
+ public static void print() {
+ System.out.println(MESSAGE);
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/RecompilationTest.java b/test/hotspot/jtreg/compiler/aot/RecompilationTest.java
new file mode 100644
index 000000000..6ab10c681
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/RecompilationTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.RecompilationTest
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname libRecompilationTest1.so
+ * -class compiler.whitebox.SimpleTestCaseHelper
+ * -extraopt -Dgraal.TieredAOT=true -extraopt -Dgraal.ProfileSimpleMethods=true
+ * -extraopt -Dgraal.ProbabilisticProfiling=false
+ * -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:.
+ * -extraopt -XX:-UseCompressedOops
+ * -extraopt -XX:CompileCommand=dontinline,compiler.whitebox.SimpleTestCaseHelper::*
+ * @run driver compiler.aot.AotCompiler -libname libRecompilationTest2.so
+ * -class compiler.whitebox.SimpleTestCaseHelper
+ * -extraopt -Dgraal.TieredAOT=false
+ * -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:.
+ * -extraopt -XX:-UseCompressedOops
+ * -extraopt -XX:CompileCommand=dontinline,compiler.whitebox.SimpleTestCaseHelper::*
+ * @run main/othervm -Xmixed -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT -XX:-TieredCompilation
+ * -XX:-UseCounterDecay -XX:-UseCompressedOops
+ * -XX:-Inline
+ * -XX:AOTLibrary=./libRecompilationTest2.so -Xbootclasspath/a:.
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * -Dcompiler.aot.RecompilationTest.check_level=-2
+ * compiler.aot.RecompilationTest
+ * @summary check if recompilation after aot goes fine
+ */
+
+ /* having whitebox-related options for aot compiler is a temporary solution,
+ because of JDK-8146201
+ */
+
+package compiler.aot;
+
+import compiler.whitebox.CompilerWhiteBoxTest;
+import java.lang.reflect.Executable;
+import jdk.test.lib.Asserts;
+
+public final class RecompilationTest extends CompilerWhiteBoxTest {
+ private static final int CHECK_LEVEL = Integer.getInteger(
+ "compiler.aot.RecompilationTest.check_level");
+
+ public static void main(String args[]) {
+ CompilerWhiteBoxTest.main(RecompilationTest::new, args);
+ }
+
+ private RecompilationTest(TestCase testCase) {
+ super(testCase);
+ }
+
+ @Override
+ protected void test() throws Exception {
+ if (testCase.isOsr()) {
+ /* aot compiler is not using osr compilation */
+ System.out.println("Skipping OSR case");
+ return;
+ }
+ Executable e = testCase.getExecutable();
+ Asserts.assertTrue(WHITE_BOX.isMethodCompiled(e),
+ testCase.name() + ": an executable expected to be compiled");
+ Asserts.assertEQ(WHITE_BOX.getMethodCompilationLevel(e),
+ COMP_LEVEL_AOT,
+ String.format("%s: unexpected compilation level at start",
+ testCase.name()));
+ compile();
+ Asserts.assertTrue(WHITE_BOX.isMethodCompiled(e), testCase.name()
+ + ": method expected to be compiled");
+ /* a case with AOT'ed code checks exact compilation level equality
+ while another case checks minimum level and if method compiled
+ because there might be different compilation level transitions */
+ if (CHECK_LEVEL != COMP_LEVEL_AOT) {
+ Asserts.assertGTE(WHITE_BOX.getMethodCompilationLevel(e),
+ CHECK_LEVEL,
+ String.format("%s: expected compilation level"
+ + " after compilation to be no less than %d for %s",
+ testCase.name(), CHECK_LEVEL, testCase.name()));
+ } else {
+ Asserts.assertEQ(WHITE_BOX.getMethodCompilationLevel(e),
+ COMP_LEVEL_AOT, String.format("%s: expected compilation"
+ + " level after compilation to be equal to %d for %s",
+ testCase.name(), COMP_LEVEL_AOT, testCase.name()));
+ }
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/SharedUsageTest.java b/test/hotspot/jtreg/compiler/aot/SharedUsageTest.java
new file mode 100644
index 000000000..ee0a4aac6
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/SharedUsageTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.SharedUsageTest
+ * compiler.aot.AotCompiler
+ * @run driver compiler.aot.AotCompiler -libname libSharedUsageTest.so
+ * -class compiler.aot.SharedUsageTest
+ * -extraopt -XX:-UseCompressedOops
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./libSharedUsageTest.so
+ * -XX:-UseCompressedOops
+ * -Dcompiler.aot.SharedUsageTest.parent=true
+ * compiler.aot.SharedUsageTest
+ * @summary check if .so can be successfully shared with 2 java processes
+ */
+
+package compiler.aot;
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.ExitCode;
+import jdk.test.lib.Utils;
+import jdk.test.lib.cli.CommandLineOptionTest;
+
+public class SharedUsageTest {
+ private static final String HELLO_MSG = "HelloWorld";
+ private static final boolean ADD_TEST_VM_OPTION = false;
+ private static boolean shouldBeFalseInParent = false;
+ private static final boolean IS_PARENT = Boolean.getBoolean(
+ "compiler.aot.SharedUsageTest.parent");
+
+ public static void main(String args[]) throws Throwable {
+ Asserts.assertFalse(shouldBeFalseInParent,
+ "A test invariant is broken");
+ if (IS_PARENT) {
+ /* An output of .so being used is verified after launch.
+ A respective message is triggered by PrintAOT option. */
+ CommandLineOptionTest.verifyJVMStartup(
+ new String[]{"libSharedUsageTest.so aot library",
+ HELLO_MSG}, null, "Unexpected exit code",
+ "Unexpected output", ExitCode.OK, ADD_TEST_VM_OPTION,
+ "-XX:+UnlockExperimentalVMOptions", "-XX:+UseAOT", "-XX:+PrintAOT",
+ "-Dtest.jdk=" + Utils.TEST_JDK,
+ "-XX:AOTLibrary=./libSharedUsageTest.so",
+ SharedUsageTest.class.getName());
+ Asserts.assertFalse(shouldBeFalseInParent, "A static member got "
+ + "unexpectedly changed");
+ } else {
+ shouldBeFalseInParent = true;
+ Asserts.assertTrue(shouldBeFalseInParent, "A static member wasn't"
+ + "changed as expected");
+ System.out.println(HELLO_MSG);
+ }
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/TestHeapBase.java b/test/hotspot/jtreg/compiler/aot/TestHeapBase.java
new file mode 100644
index 000000000..7662e1dd7
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/TestHeapBase.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2023, Arm Limited. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8244164
+ * @requires vm.aot & vm.bits == 64
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.TestHeapBase
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname libTestHeapBase.so
+ * -class compiler.aot.TestHeapBase
+ * -compile compiler.aot.TestHeapBase.test()V
+ * -extraopt -XX:+UseCompressedOops -extraopt -Xmx1g
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:+UseCompressedOops -XX:HeapBaseMinAddress=32g
+ * -XX:AOTLibrary=./libTestHeapBase.so -Xbootclasspath/a:.
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xlog:aot+class+load=trace
+ * compiler.aot.TestHeapBase
+ * @summary check for crash when jaotc is run with zero-based compressed oops then
+ * generated code is loaded in vm with non-zero-based compressed oops.
+ */
+
+package compiler.aot;
+
+import java.lang.reflect.Method;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.Utils;
+import jdk.test.whitebox.WhiteBox;
+import compiler.whitebox.CompilerWhiteBoxTest;
+
+public final class TestHeapBase {
+ private static final String TEST_METHOD = "test";
+ private static final WhiteBox WB = WhiteBox.getWhiteBox();
+ private final Method testMethod;
+
+ private TestHeapBase() {
+ try {
+ testMethod = getClass().getDeclaredMethod(TEST_METHOD);
+ } catch (NoSuchMethodException e) {
+ throw new Error("TEST BUG: no test method found", e);
+ }
+ }
+
+ public static void main(String args[]) {
+ new TestHeapBase().test();
+ }
+
+ private void test() {
+ System.out.println("Hello, World!");
+
+ Asserts.assertTrue(WB.isMethodCompiled(testMethod),
+ "Method expected to be compiled");
+ Asserts.assertEQ(WB.getMethodCompilationLevel(testMethod),
+ CompilerWhiteBoxTest.COMP_LEVEL_AOT,
+ "Expected method to be AOT compiled");
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2AotTest.java
new file mode 100644
index 000000000..a99063674
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2AotTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ * java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeDynamic
+ * jdk.test.whitebox.WhiteBox
+ * @run driver compiler.calls.common.InvokeDynamicPatcher
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname AotInvokeDynamic2AotTest.so
+ * -class compiler.calls.common.InvokeDynamic
+ * -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:.
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeDynamic2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeDynamic
+ * -checkCallerCompileLevel -2 -checkCalleeCompileLevel -2
+ * @summary check calls from aot to aot code using invokedynamic
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2CompiledTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2CompiledTest.java
new file mode 100644
index 000000000..440afc469
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2CompiledTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ * java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeDynamic
+ * jdk.test.whitebox.WhiteBox
+ * @run driver compiler.calls.common.InvokeDynamicPatcher
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname AotInvokeDynamic2CompiledTest.so
+ * -class compiler.calls.common.InvokeDynamic
+ * -compile compiler.calls.common.InvokeDynamic.caller()V
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeDynamic2CompiledTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeDynamic -compileCallee 1
+ * -checkCalleeCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeDynamic2CompiledTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeDynamic -compileCallee 4
+ * -checkCalleeCompileLevel 4
+ * @summary check calls from aot to jit-compiled code using invokedynamic
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2InterpretedTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2InterpretedTest.java
new file mode 100644
index 000000000..d0fedf37a
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2InterpretedTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ * java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeDynamic
+ * jdk.test.whitebox.WhiteBox
+ * @run driver compiler.calls.common.InvokeDynamicPatcher
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler
+ * -libname AotInvokeDynamic2InterpretedTest.so
+ * -class compiler.calls.common.InvokeDynamic
+ * -compile compiler.calls.common.InvokeDynamic.caller()V
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions
+ * -XX:AOTLibrary=./AotInvokeDynamic2InterpretedTest.so
+ * -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::callee
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * -XX:+UseAOT compiler.calls.common.InvokeDynamic -checkCallerCompileLevel -2
+ * @summary check calls from aot to interpreted code using invokedynamic
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2NativeTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2NativeTest.java
new file mode 100644
index 000000000..3f137af95
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2NativeTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ * java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeDynamic
+ * jdk.test.whitebox.WhiteBox
+ * @run driver compiler.calls.common.InvokeDynamicPatcher
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname AotInvokeDynamic2NativeTest.so
+ * -class compiler.calls.common.InvokeDynamic
+ * -compile compiler.calls.common.InvokeDynamic.caller()V
+ * @run main/othervm/native -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeDynamic2NativeTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeDynamic -nativeCallee -checkCallerCompileLevel -2
+ * @summary check calls from aot to native code using invokedynamic
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeInterface2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeInterface2AotTest.java
new file mode 100644
index 000000000..647f056bf
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeInterface2AotTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeInterface
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname AotInvokeInterface2AotTest.so
+ * -class compiler.calls.common.InvokeInterface
+ * -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:.
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeInterface2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeInterface
+ * -checkCallerCompileLevel -2 -checkCalleeCompileLevel -2
+ * @summary check calls from aot to aot code using invokeinterface
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeInterface2CompiledTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeInterface2CompiledTest.java
new file mode 100644
index 000000000..e980fb1bc
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeInterface2CompiledTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeInterface
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler
+ * -libname AotInvokeInterface2CompiledTest.so
+ * -class compiler.calls.common.InvokeInterface
+ * -compile compiler.calls.common.InvokeInterface.caller()V
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeInterface2CompiledTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeInterface -compileCallee 1
+ * -checkCalleeCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeInterface2CompiledTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeInterface -compileCallee 4
+ * -checkCalleeCompileLevel 4
+ * @summary check calls from aot to jit-compiled code using invokeinterface
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeInterface2InterpretedTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeInterface2InterpretedTest.java
new file mode 100644
index 000000000..66ab8ab9a
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeInterface2InterpretedTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeInterface
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler
+ * -libname AotInvokeInterface2InterpretedTest.so
+ * -class compiler.calls.common.InvokeInterface
+ * -compile compiler.calls.common.InvokeInterface.caller()V
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeInterface2InterpretedTest.so
+ * -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::callee
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeInterface -checkCallerCompileLevel -2
+ * @summary check calls from aot to interpreted code using invokeinterface
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeInterface2NativeTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeInterface2NativeTest.java
new file mode 100644
index 000000000..47fe30fd8
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeInterface2NativeTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeInterface
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname AotInvokeInterface2NativeTest.so
+ * -class compiler.calls.common.InvokeInterface
+ * -compile compiler.calls.common.InvokeInterface.caller()V
+ * @run main/othervm/native -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeInterface2NativeTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeInterface -nativeCallee -checkCallerCompileLevel -2
+ * @summary check calls from aot to native code using invokeinterface
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeSpecial2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeSpecial2AotTest.java
new file mode 100644
index 000000000..de91a28db
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeSpecial2AotTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeSpecial
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname AotInvokeSpecial2AotTest.so
+ * -class compiler.calls.common.InvokeSpecial
+ * -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:.
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeSpecial2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeSpecial
+ * -checkCallerCompileLevel -2 -checkCalleeCompileLevel -2
+ * @summary check calls from aot to aot code using invokespecial
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeSpecial2CompiledTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeSpecial2CompiledTest.java
new file mode 100644
index 000000000..b2b846f3d
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeSpecial2CompiledTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeSpecial
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname AotInvokeSpecial2CompiledTest.so
+ * -class compiler.calls.common.InvokeSpecial
+ * -compile compiler.calls.common.InvokeSpecial.caller()V
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeSpecial2CompiledTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeSpecial -compileCallee 1
+ * -checkCalleeCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeSpecial2CompiledTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeSpecial -compileCallee 4
+ * -checkCalleeCompileLevel 4
+ * @summary check calls from aot to jit-compiled code using invokespecial
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeSpecial2InterpretedTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeSpecial2InterpretedTest.java
new file mode 100644
index 000000000..7c401741e
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeSpecial2InterpretedTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeSpecial
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler
+ * -libname AotInvokeSpecial2InterpretedTest.so
+ * -class compiler.calls.common.InvokeSpecial
+ * -compile compiler.calls.common.InvokeSpecial.caller()V
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeSpecial2InterpretedTest.so
+ * -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::callee
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeSpecial -checkCallerCompileLevel -2
+ * @summary check calls from aot to interpreted code using invokespecial
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeSpecial2NativeTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeSpecial2NativeTest.java
new file mode 100644
index 000000000..abaf49288
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeSpecial2NativeTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeSpecial
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname AotInvokeSpecial2NativeTest.so
+ * -class compiler.calls.common.InvokeSpecial
+ * -compile compiler.calls.common.InvokeSpecial.caller()V
+ * @run main/othervm/native -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeSpecial2NativeTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeSpecial -nativeCallee -checkCallerCompileLevel -2
+ * @summary check calls from aot to interpreted code using invokespecial
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeStatic2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeStatic2AotTest.java
new file mode 100644
index 000000000..3f9ab84eb
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeStatic2AotTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeStatic
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname AotInvokeStatic2AotTest.so
+ * -class compiler.calls.common.InvokeStatic
+ * -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:.
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeStatic2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeStatic
+ * -checkCallerCompileLevel -2 -checkCalleeCompileLevel -2
+ * @summary check calls from aot to aot code using invokestatic
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeStatic2CompiledTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeStatic2CompiledTest.java
new file mode 100644
index 000000000..a69b5c31d
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeStatic2CompiledTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeStatic
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname AotInvokeStatic2CompiledTest.so
+ * -class compiler.calls.common.InvokeStatic
+ * -compile compiler.calls.common.InvokeStatic.caller()V
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeStatic2CompiledTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeStatic -compileCallee 1
+ * -checkCalleeCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeStatic2CompiledTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeStatic -compileCallee 4
+ * -checkCalleeCompileLevel 4
+ * @summary check calls from aot to jit-compiled code using invokestatic
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeStatic2InterpretedTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeStatic2InterpretedTest.java
new file mode 100644
index 000000000..12ad2e786
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeStatic2InterpretedTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeStatic
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler
+ * -libname AotInvokeStatic2InterpretedTest.so
+ * -class compiler.calls.common.InvokeStatic
+ * -compile compiler.calls.common.InvokeStatic.caller()V
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeStatic2InterpretedTest.so
+ * -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::callee
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeStatic -checkCallerCompileLevel -2
+ * @summary check calls from aot to interpreted code using invokestatic
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeStatic2NativeTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeStatic2NativeTest.java
new file mode 100644
index 000000000..3ccc920e4
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeStatic2NativeTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeStatic
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname AotInvokeStatic2NativeTest.so
+ * -class compiler.calls.common.InvokeStatic
+ * -compile compiler.calls.common.InvokeStatic.caller()V
+ * @run main/othervm/native -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeStatic2NativeTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeStatic -nativeCallee -checkCallerCompileLevel -2
+ * @summary check calls from aot to native code using invokestatic
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeVirtual2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeVirtual2AotTest.java
new file mode 100644
index 000000000..8fc2c9ae0
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeVirtual2AotTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeVirtual
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname AotInvokeVirtual2AotTest.so
+ * -class compiler.calls.common.InvokeVirtual
+ * -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:.
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeVirtual2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeVirtual
+ * -checkCallerCompileLevel -2 -checkCalleeCompileLevel -2
+ * @summary check calls from aot to aot code, using invokevirtual
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeVirtual2CompiledTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeVirtual2CompiledTest.java
new file mode 100644
index 000000000..10251b9b0
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeVirtual2CompiledTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeVirtual
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname AotInvokeVirtual2CompiledTest.so
+ * -class compiler.calls.common.InvokeVirtual
+ * -compile compiler.calls.common.InvokeVirtual.caller()V
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeVirtual2CompiledTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeVirtual -compileCallee 1
+ * -checkCalleeCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeVirtual2CompiledTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeVirtual -compileCallee 4
+ * -checkCalleeCompileLevel 4
+ * @summary check calls from aot to jit-compiled code, using invokevirtual
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeVirtual2InterpretedTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeVirtual2InterpretedTest.java
new file mode 100644
index 000000000..754d5fef7
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeVirtual2InterpretedTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeVirtual
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler
+ * -libname AotInvokeVirtual2InterpretedTest.so
+ * -class compiler.calls.common.InvokeVirtual
+ * -compile compiler.calls.common.InvokeVirtual.caller()V
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeVirtual2InterpretedTest.so
+ * -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::callee
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeVirtual -checkCallerCompileLevel -2
+ * @summary check calls from aot to interpreted code, using invokevirtual
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeVirtual2NativeTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeVirtual2NativeTest.java
new file mode 100644
index 000000000..6761e19d1
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeVirtual2NativeTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeVirtual
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname AotInvokeVirtual2NativeTest.so
+ * -class compiler.calls.common.InvokeVirtual
+ * -compile compiler.calls.common.InvokeVirtual.caller()V
+ * @run main/othervm/native -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./AotInvokeVirtual2NativeTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeVirtual -nativeCallee -checkCallerCompileLevel -2
+ * @summary check calls from aot to native code, using invokevirtual
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeDynamic2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeDynamic2AotTest.java
new file mode 100644
index 000000000..20e24378b
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeDynamic2AotTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ * java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeDynamic
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.calls.common.InvokeDynamicPatcher
+ * @run driver compiler.aot.AotCompiler -libname CompiledInvokeDynamic2AotTest.so
+ * -class compiler.calls.common.InvokeDynamic
+ * -compile compiler.calls.common.InvokeDynamic.callee.*
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./CompiledInvokeDynamic2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeDynamic -compileCaller 1
+ * -checkCalleeCompileLevel -2 -checkCallerCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./CompiledInvokeDynamic2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeDynamic -compileCaller 4
+ * -checkCallerCompileLevel 4 -checkCalleeCompileLevel -2
+ * @summary check calls from jit-compiled to aot code using invokedynamic
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeInterface2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeInterface2AotTest.java
new file mode 100644
index 000000000..78cb53589
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeInterface2AotTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeInterface
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler
+ * -libname CompiledInvokeInterface2AotTest.so
+ * -class compiler.calls.common.InvokeInterface
+ * -compile compiler.calls.common.InvokeInterface.callee.*
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./CompiledInvokeInterface2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeInterface -compileCaller 1
+ * -checkCalleeCompileLevel -2 -checkCallerCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./CompiledInvokeInterface2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeInterface -compileCaller 4
+ * -checkCallerCompileLevel 4 -checkCalleeCompileLevel -2
+ * @summary check calls from jit-compiled to aot code using invokeinterface
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeSpecial2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeSpecial2AotTest.java
new file mode 100644
index 000000000..04ae4ecac
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeSpecial2AotTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeSpecial
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname CompiledInvokeSpecial2AotTest.so
+ * -class compiler.calls.common.InvokeSpecial
+ * -compile compiler.calls.common.InvokeSpecial.callee.*
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./CompiledInvokeSpecial2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeSpecial -compileCaller 1
+ * -checkCalleeCompileLevel -2 -checkCallerCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./CompiledInvokeSpecial2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeSpecial -compileCaller 4
+ * -checkCallerCompileLevel 4 -checkCalleeCompileLevel -2
+ * @summary check calls from jit-compiled to aot code using invokespecial
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeStatic2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeStatic2AotTest.java
new file mode 100644
index 000000000..d07f7d5e0
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeStatic2AotTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeStatic
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname CompiledInvokeStatic2AotTest.so
+ * -class compiler.calls.common.InvokeStatic
+ * -compile compiler.calls.common.InvokeStatic.callee.*
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./CompiledInvokeStatic2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeStatic -compileCaller 1
+ * -checkCalleeCompileLevel -2 -checkCallerCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./CompiledInvokeStatic2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeStatic -compileCaller 4
+ * -checkCallerCompileLevel 4 -checkCalleeCompileLevel -2
+ * @summary check calls from jit-compiled to aot code using invokestatic
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeVirtual2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeVirtual2AotTest.java
new file mode 100644
index 000000000..807526e30
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromCompiled/CompiledInvokeVirtual2AotTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeVirtual
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname CompiledInvokeVirtual2AotTest.so
+ * -class compiler.calls.common.InvokeVirtual
+ * -compile compiler.calls.common.InvokeVirtual.callee.*
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./CompiledInvokeVirtual2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeVirtual -compileCaller 1
+ * -checkCalleeCompileLevel -2 -checkCallerCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./CompiledInvokeVirtual2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeVirtual -compileCaller 4
+ * -checkCallerCompileLevel 4 -checkCalleeCompileLevel -2
+ * @summary check calls from jit-compiled to aot code using invokevirtual
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeDynamic2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeDynamic2AotTest.java
new file mode 100644
index 000000000..c08bb7382
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeDynamic2AotTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ * java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeDynamic
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.calls.common.InvokeDynamicPatcher
+ * @run driver compiler.aot.AotCompiler
+ * -libname InterpretedInvokeDynamic2AotTest.so
+ * -class compiler.calls.common.InvokeDynamic
+ * -compile compiler.calls.common.InvokeDynamic.callee.*
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./InterpretedInvokeDynamic2AotTest.so
+ * -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::caller
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeDynamic -checkCalleeCompileLevel -2
+ * @summary check calls from interpreted to aot code using invokedynamic
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeInterface2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeInterface2AotTest.java
new file mode 100644
index 000000000..320c1072e
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeInterface2AotTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeInterface
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler
+ * -libname InterpretedInvokeInterface2AotTest.so
+ * -class compiler.calls.common.InvokeInterface
+ * -compile compiler.calls.common.InvokeInterface.callee.*
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./InterpretedInvokeInterface2AotTest.so
+ * -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::caller
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeInterface -checkCalleeCompileLevel -2
+ * @summary check calls from interpreted to aot code using invokeinterface
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeSpecial2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeSpecial2AotTest.java
new file mode 100644
index 000000000..bd591c2fc
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeSpecial2AotTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeSpecial
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler
+ * -libname InterpretedInvokeSpecial2AotTest.so
+ * -class compiler.calls.common.InvokeSpecial
+ * -compile compiler.calls.common.InvokeSpecial.callee.*
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./InterpretedInvokeSpecial2AotTest.so
+ * -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::caller
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeSpecial -checkCalleeCompileLevel -2
+ * @summary check calls from interpreted to aot code using invokespecial
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeStatic2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeStatic2AotTest.java
new file mode 100644
index 000000000..090ee2af4
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeStatic2AotTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeStatic
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler
+ * -libname InterpretedInvokeStatic2AotTest.so
+ * -class compiler.calls.common.InvokeStatic
+ * -compile compiler.calls.common.InvokeStatic.callee.*
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./InterpretedInvokeStatic2AotTest.so
+ * -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::caller
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeStatic -checkCalleeCompileLevel -2
+ * @summary check calls from interpreted to aot code using invokestatic
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeVirtual2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeVirtual2AotTest.java
new file mode 100644
index 000000000..31cb0d8c5
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromInterpreted/InterpretedInvokeVirtual2AotTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeVirtual
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler
+ * -libname InterpretedInvokeVirtual2AotTest.so
+ * -class compiler.calls.common.InvokeVirtual
+ * -compile compiler.calls.common.InvokeVirtual.callee.*
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./InterpretedInvokeVirtual2AotTest.so
+ * -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::caller
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeVirtual -checkCalleeCompileLevel -2
+ * @summary check calls from interpreted to aot code using invokevirtual
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromNative/NativeInvokeSpecial2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromNative/NativeInvokeSpecial2AotTest.java
new file mode 100644
index 000000000..705e3c818
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromNative/NativeInvokeSpecial2AotTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeSpecial
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname NativeInvokeSpecial2AotTest.so
+ * -class compiler.calls.common.InvokeSpecial
+ * -compile compiler.calls.common.InvokeSpecial.callee.*
+ * @run main/othervm/native -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./NativeInvokeSpecial2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeSpecial -nativeCaller -checkCalleeCompileLevel -2
+ * @summary check calls from native to aot code using invokespecial
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromNative/NativeInvokeStatic2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromNative/NativeInvokeStatic2AotTest.java
new file mode 100644
index 000000000..ac810313b
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromNative/NativeInvokeStatic2AotTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeStatic
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname NativeInvokeStatic2AotTest.so
+ * -class compiler.calls.common.InvokeStatic
+ * -compile compiler.calls.common.InvokeStatic.callee.*
+ * @run main/othervm/native -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./NativeInvokeStatic2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeStatic -nativeCaller -checkCalleeCompileLevel -2
+ * @summary check calls from native to aot code using invokestatic
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromNative/NativeInvokeVirtual2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromNative/NativeInvokeVirtual2AotTest.java
new file mode 100644
index 000000000..8d8ab9f18
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/calls/fromNative/NativeInvokeVirtual2AotTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeVirtual
+ * jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run driver compiler.aot.AotCompiler -libname NativeInvokeVirtual2AotTest.so
+ * -class compiler.calls.common.InvokeVirtual
+ * -compile compiler.calls.common.InvokeVirtual.callee.*
+ * @run main/othervm/native -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * -XX:AOTLibrary=./NativeInvokeVirtual2AotTest.so
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * compiler.calls.common.InvokeVirtual -nativeCaller -checkCalleeCompileLevel -2
+ * @summary check calls from native to aot code using invokevirtual
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/cli/AotLibraryNegativeBase.java b/test/hotspot/jtreg/compiler/aot/cli/AotLibraryNegativeBase.java
new file mode 100644
index 000000000..56a6ecda6
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/AotLibraryNegativeBase.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot.cli;
+
+import compiler.aot.HelloWorldPrinter;
+import jdk.test.lib.process.ExitCode;
+import jdk.test.lib.cli.CommandLineOptionTest;
+
+public class AotLibraryNegativeBase {
+ private static final String[] UNEXPECTED_MESSAGES = new String[] {
+ HelloWorldPrinter.MESSAGE
+ };
+
+ public static void launchTest(String option, String expectedMessages[]) {
+ try {
+ boolean addTestVMOptions = true;
+ CommandLineOptionTest.verifyJVMStartup(expectedMessages,
+ UNEXPECTED_MESSAGES,
+ "Unexpected exit code using " + option,
+ "Unexpected output using " + option, ExitCode.FAIL,
+ addTestVMOptions, "-XX:+UnlockExperimentalVMOptions", "-XX:+UseAOT",
+ "-XX:+PrintAOT", option, HelloWorldPrinter.class.getName());
+ } catch (Throwable t) {
+ throw new Error("Problems executing test using " + option
+ + ": " + t, t);
+ }
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/DisabledAOTWithLibraryTest.java b/test/hotspot/jtreg/compiler/aot/cli/DisabledAOTWithLibraryTest.java
new file mode 100644
index 000000000..433231de3
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/DisabledAOTWithLibraryTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @build compiler.aot.cli.DisabledAOTWithLibraryTest
+ * compiler.aot.AotCompiler
+ * @run driver compiler.aot.AotCompiler -libname libDisabledAOTWithLibraryTest.so
+ * -class compiler.aot.HelloWorldPrinter
+ * -compile compiler.aot.HelloWorldPrinter.print()V
+ * @run driver compiler.aot.cli.DisabledAOTWithLibraryTest
+ * @summary check if providing aot library with aot disabled is handled properly
+ */
+
+package compiler.aot.cli;
+
+import compiler.aot.HelloWorldPrinter;
+import jdk.test.lib.process.ExitCode;
+import jdk.test.lib.cli.CommandLineOptionTest;
+
+public class DisabledAOTWithLibraryTest {
+ private final static String LIB_NAME = "libDisabledAOTWithLibraryTest.so";
+ private final static String[] UNEXPECTED_MESSAGES = new String[] {
+ LIB_NAME + " aot library"
+ };
+
+ private final static String[] EXPECTED_MESSAGES = new String[] {
+ HelloWorldPrinter.MESSAGE
+ };
+
+ public static void main(String args[]) {
+ try {
+ boolean addTestVMOptions = true;
+ CommandLineOptionTest.verifyJVMStartup(EXPECTED_MESSAGES,
+ UNEXPECTED_MESSAGES, "Unexpected exit code",
+ "Unexpected output", ExitCode.OK, addTestVMOptions,
+ "-XX:+UnlockExperimentalVMOptions", "-XX:-UseAOT", "-XX:+PrintAOT",
+ "-XX:AOTLibrary=./" + LIB_NAME,
+ HelloWorldPrinter.class.getName());
+ } catch (Throwable t) {
+ throw new Error("Problems executing test " + t, t);
+ }
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/IncorrectAOTLibraryTest.java b/test/hotspot/jtreg/compiler/aot/cli/IncorrectAOTLibraryTest.java
new file mode 100644
index 000000000..a5b7ea9ca
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/IncorrectAOTLibraryTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.lib.helpers.ClassFileInstaller
+ * @run driver compiler.aot.cli.IncorrectAOTLibraryTest
+ * @summary check if incorrect aot library is handled properly
+ */
+
+package compiler.aot.cli;
+
+import java.nio.file.Paths;
+
+public class IncorrectAOTLibraryTest {
+ private static final String OPTION
+ = "-XX:AOTLibrary=./" + Paths.get("jdk", "test", "lib", "helpers", "ClassFileInstaller.class").toString();
+ private static final String[] EXPECTED_MESSAGES = new String[] {
+ "error opening file:"
+ };
+
+ public static void main(String args[]) {
+ AotLibraryNegativeBase.launchTest(OPTION, EXPECTED_MESSAGES);
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/MultipleAOTLibraryTest.java b/test/hotspot/jtreg/compiler/aot/cli/MultipleAOTLibraryTest.java
new file mode 100644
index 000000000..1423c55dc
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/MultipleAOTLibraryTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.cli.MultipleAOTLibraryTest
+ * compiler.aot.AotCompiler
+ * @run driver compiler.aot.AotCompiler
+ * -libname libMultipleAOTLibraryTest1.so
+ * -class compiler.aot.HelloWorldPrinter
+ * -compile compiler.aot.HelloWorldPrinter.*
+ * -extraopt -XX:+UseCompressedOops
+ * @run driver compiler.aot.AotCompiler
+ * -libname libMultipleAOTLibraryTest2.so
+ * -class compiler.aot.HelloWorldPrinter
+ * -compile compiler.aot.HelloWorldPrinter.print()V
+ * -extraopt -XX:+UseCompressedOops
+ * @run driver compiler.aot.cli.MultipleAOTLibraryTest -XX:+UseCompressedOops
+ * @run driver compiler.aot.AotCompiler -libname libMultipleAOTLibraryTest1.so
+ * -class compiler.aot.HelloWorldPrinter
+ * -compile compiler.aot.HelloWorldPrinter.*
+ * -extraopt -XX:-UseCompressedOops
+ * @run driver compiler.aot.AotCompiler -libname libMultipleAOTLibraryTest2.so
+ * -class compiler.aot.HelloWorldPrinter
+ * -compile compiler.aot.HelloWorldPrinter.print()V
+ * -extraopt -XX:-UseCompressedOops
+ * @run driver compiler.aot.cli.MultipleAOTLibraryTest -XX:-UseCompressedOops
+ * @summary check if multiple aot libraries are loaded successfully
+ */
+
+package compiler.aot.cli;
+
+import compiler.aot.HelloWorldPrinter;
+import java.io.File;
+import java.util.Arrays;
+import jdk.test.lib.process.ExitCode;
+import jdk.test.lib.cli.CommandLineOptionTest;
+
+public final class MultipleAOTLibraryTest {
+ private final static String EXPECTED_OUTPUT[] = new String[] {
+ "libMultipleAOTLibraryTest1.so aot library",
+ "libMultipleAOTLibraryTest2.so aot library",
+ HelloWorldPrinter.MESSAGE
+ };
+ private final static String UNEXPECTED_OUTPUT[] = null;
+
+ public static void main(String args[]) {
+ new MultipleAOTLibraryTest().runTest(args);
+ }
+
+ private void runTest(String args[]) {
+ try {
+ boolean addTestVMOptions = true;
+ String[] allArgs = Arrays.copyOf(args, args.length + 5);
+ allArgs[args.length] = "-XX:+UnlockExperimentalVMOptions";
+ allArgs[args.length + 1] = "-XX:AOTLibrary="
+ + "." + File.separator
+ + "libMultipleAOTLibraryTest1.so"
+ + File.pathSeparator
+ + "." + File.separator
+ + "libMultipleAOTLibraryTest2.so";
+ allArgs[args.length + 2] = "-XX:+PrintAOT";
+ allArgs[args.length + 3] = "-XX:+UseAOT";
+ allArgs[args.length + 4] = HelloWorldPrinter.class.getName();
+ CommandLineOptionTest.verifyJVMStartup(EXPECTED_OUTPUT,
+ UNEXPECTED_OUTPUT, "Unexpected exit code",
+ "Unexpected output", ExitCode.OK, addTestVMOptions,
+ allArgs);
+ } catch (Throwable t) {
+ throw new Error("Problems executing test: " + t, t);
+ }
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/NonExistingAOTLibraryTest.java b/test/hotspot/jtreg/compiler/aot/cli/NonExistingAOTLibraryTest.java
new file mode 100644
index 000000000..1d317643b
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/NonExistingAOTLibraryTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @run driver compiler.aot.cli.NonExistingAOTLibraryTest
+ * @summary check if non-existing aot library is handled properly
+ */
+
+package compiler.aot.cli;
+
+import java.io.File;
+
+public class NonExistingAOTLibraryTest {
+ private static final String PATH = "./NonExisting.so";
+ private static final String OPTION = "-XX:AOTLibrary=" + PATH;
+ private static final String[] EXPECTED_MESSAGES = new String[] {
+ "error opening file"
+ };
+
+ public static void main(String args[]) {
+ if (new File(PATH).exists()) {
+ throw new Error("TESTBUG: " + PATH + " unexpectedly exists");
+ }
+ AotLibraryNegativeBase.launchTest(OPTION, EXPECTED_MESSAGES);
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/SingleAOTLibraryTest.java b/test/hotspot/jtreg/compiler/aot/cli/SingleAOTLibraryTest.java
new file mode 100644
index 000000000..79403d199
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/SingleAOTLibraryTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib / /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.cli.SingleAOTLibraryTest
+ * compiler.aot.AotCompiler
+ * @run driver compiler.aot.AotCompiler -libname libSingleAOTLibraryTest.so
+ * -class compiler.aot.HelloWorldPrinter
+ * -compile compiler.aot.HelloWorldPrinter.print()V
+ * -extraopt -XX:+UseCompressedOops
+ * @run driver compiler.aot.cli.SingleAOTLibraryTest -XX:+UseCompressedOops
+ * @run driver compiler.aot.AotCompiler -libname libSingleAOTLibraryTest.so
+ * -class compiler.aot.HelloWorldPrinter
+ * -compile compiler.aot.HelloWorldPrinter.print()V
+ * -extraopt -XX:-UseCompressedOops
+ * @run driver compiler.aot.cli.SingleAOTLibraryTest -XX:-UseCompressedOops
+ * @summary check if single aot library is loaded successfully
+ */
+
+package compiler.aot.cli;
+
+import compiler.aot.HelloWorldPrinter;
+import jdk.test.lib.process.ExitCode;
+import jdk.test.lib.cli.CommandLineOptionTest;
+
+public final class SingleAOTLibraryTest {
+ private static final String[] EXPECTED_MESSAGES = new String[] {
+ "libSingleAOTLibraryTest.so aot library",
+ HelloWorldPrinter.MESSAGE
+ };
+ private static final String[] UNEXPECTED_MESSAGES = null;
+ public static void main(String args[]) {
+ if (args.length == 1) {
+ new SingleAOTLibraryTest().runTest(args[0]);
+ } else {
+ throw new Error("Test expects 1 parameter");
+ }
+ }
+
+ private void runTest(String arg) {
+ try {
+ boolean addTestVMOptions = true;
+ CommandLineOptionTest.verifyJVMStartup(EXPECTED_MESSAGES,
+ UNEXPECTED_MESSAGES, "Unexpected exit code using " + arg,
+ "Unexpected output using " + arg, ExitCode.OK,
+ addTestVMOptions, "-XX:+UnlockExperimentalVMOptions", "-XX:+UseAOT",
+ "-XX:+PrintAOT", arg, "-XX:AOTLibrary=./libSingleAOTLibraryTest.so",
+ HelloWorldPrinter.class.getName());
+ } catch (Throwable t) {
+ throw new Error("Problems executing test: " + t, t);
+ }
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/SingleAOTOptionTest.java b/test/hotspot/jtreg/compiler/aot/cli/SingleAOTOptionTest.java
new file mode 100644
index 000000000..cbc065cbf
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/SingleAOTOptionTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.cli.SingleAOTOptionTest
+ * compiler.aot.AotCompiler
+ * @run driver compiler.aot.AotCompiler -libname libSingleAOTOptionTest.so
+ * -class compiler.aot.HelloWorldPrinter
+ * -compile compiler.aot.HelloWorldPrinter.print()V
+ * -extraopt -XX:+UseCompressedOops
+ * @run driver compiler.aot.cli.SingleAOTOptionTest -XX:+UseCompressedOops
+ * -XX:+UnlockExperimentalVMOptions -XX:AOTLibrary=./libSingleAOTOptionTest.so
+ * @run main compiler.aot.cli.SingleAOTOptionTest
+ * -XX:+UseCompressedOops -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * @run driver compiler.aot.AotCompiler -libname libSingleAOTOptionTest.so
+ * -class compiler.aot.HelloWorldPrinter
+ * -compile compiler.aot.HelloWorldPrinter.print()V
+ * -extraopt -XX:-UseCompressedOops
+ * @run driver compiler.aot.cli.SingleAOTOptionTest -XX:-UseCompressedOops
+ * -XX:+UnlockExperimentalVMOptions -XX:AOTLibrary=./libSingleAOTOptionTest.so
+ * @run driver compiler.aot.cli.SingleAOTOptionTest
+ * -XX:-UseCompressedOops -XX:+UnlockExperimentalVMOptions -XX:+UseAOT
+ * @summary check if specifying only one aot option handled properly
+ */
+
+package compiler.aot.cli;
+
+import compiler.aot.HelloWorldPrinter;
+import jdk.test.lib.process.ExitCode;
+import jdk.test.lib.cli.CommandLineOptionTest;
+
+public class SingleAOTOptionTest {
+ private static final String[] EXPECTED_MESSAGES = new String[] {
+ HelloWorldPrinter.MESSAGE
+ };
+ private static final String[] UNEXPECTED_MESSAGES = null;
+
+ public static void main(String args[]) {
+ if (args.length == 3) {
+ new SingleAOTOptionTest().runTest(args[0], args[1], args[2]);
+ } else {
+ throw new Error("Test expects 2 parameters");
+ }
+ }
+
+ private void runTest(String arg1, String arg2, String arg3) {
+ try {
+ String exitCodeErrorMessage = String.format("Unexpected exit code "
+ + "using %s %s %s", arg1, arg2, arg3);
+ String outputErrorMessage = String.format("Unexpected output using"
+ + " %s %s", arg1, arg2, arg3);
+ boolean addTestVMOptions = true;
+ CommandLineOptionTest.verifyJVMStartup(EXPECTED_MESSAGES,
+ UNEXPECTED_MESSAGES, exitCodeErrorMessage,
+ outputErrorMessage, ExitCode.OK, addTestVMOptions, arg1,
+ arg2, arg3, HelloWorldPrinter.class.getName());
+ } catch (Throwable t) {
+ throw new Error("Problems executing test: " + t, t);
+ }
+ }
+
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/jaotc/AtFileTest.java b/test/hotspot/jtreg/compiler/aot/cli/jaotc/AtFileTest.java
new file mode 100644
index 000000000..0f14f1053
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/jaotc/AtFileTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary check at-file jaotc support
+ * @comment based on CompileClassTest with arguments wrote in 'jaotc.cmd' file
+ * @requires vm.aot
+ * @bug 8215322
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.cli.jaotc.AtFileTest
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
+ * @run driver compiler.aot.cli.jaotc.AtFileTest
+ */
+
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldOne;
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.Files;
+import java.util.List;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class AtFileTest {
+ public static void main(String[] args) throws Exception {
+ Path file = Paths.get("jaotc.cmd");
+ Files.write(file, List.of("--class-name",
+ JaotcTestHelper.getClassAotCompilationName(HelloWorldOne.class)));
+ OutputAnalyzer oa = JaotcTestHelper.compileLibrary("@" + file.toString());
+ oa.shouldHaveExitValue(0);
+ File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+ Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing");
+ Asserts.assertGT(compiledLibrary.length(), 0L, "Unexpected compiled library size");
+ JaotcTestHelper.checkLibraryUsage(HelloWorldOne.class.getName());
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/jaotc/ClasspathOptionUnknownClassTest.java b/test/hotspot/jtreg/compiler/aot/cli/jaotc/ClasspathOptionUnknownClassTest.java
new file mode 100644
index 000000000..fe03c108d
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/jaotc/ClasspathOptionUnknownClassTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library / /testlibrary/ /test/lib
+ * @modules java.base/jdk.internal.misc
+ * @compile data/HelloWorldOne.java
+ * @run driver compiler.aot.cli.jaotc.ClasspathOptionUnknownClassTest
+ * @summary check jaotc can't compile class not from classpath
+ */
+
+package compiler.aot.cli.jaotc;
+
+import java.io.File;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class ClasspathOptionUnknownClassTest {
+ public static void main(String[] args) {
+ OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--class-name", "HelloWorldOne");
+ Asserts.assertNE(oa.getExitValue(), 0, "Unexpected compilation exit code");
+ File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+ Asserts.assertFalse(compiledLibrary.exists(), "Compiler library unexpectedly exists");
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileAbsoluteDirectoryTest.java b/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileAbsoluteDirectoryTest.java
new file mode 100644
index 000000000..6e1cf3081
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileAbsoluteDirectoryTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.cli.jaotc.CompileAbsoluteDirectoryTest
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
+ * compiler.aot.cli.jaotc.data.HelloWorldTwo
+ * @run driver compiler.aot.cli.jaotc.CompileAbsoluteDirectoryTest
+ * @summary check jaotc can compile directory with classes where directory is specified by absolute path
+ * @bug 8218859
+ */
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldOne;
+import compiler.aot.cli.jaotc.data.HelloWorldTwo;
+import java.io.File;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class CompileAbsoluteDirectoryTest {
+ public static void main(String[] args) {
+ try {
+ String dir = new java.io.File(".").getAbsolutePath();
+ System.out.println("Do test --directory " + dir);
+ OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--directory", dir);
+ oa.shouldHaveExitValue(0);
+ File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+ Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing");
+ Asserts.assertGT(compiledLibrary.length(), 0L, "Unexpected compiled library size");
+ JaotcTestHelper.checkLibraryUsage(HelloWorldOne.class.getName());
+ JaotcTestHelper.checkLibraryUsage(HelloWorldTwo.class.getName());
+ } catch (Exception e) {
+ throw new Error("Can't get full path name for '.', got exception " + e, e);
+ }
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileClassTest.java b/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileClassTest.java
new file mode 100644
index 000000000..efc7cc523
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileClassTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.cli.jaotc.CompileClassTest
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
+ * @run driver compiler.aot.cli.jaotc.CompileClassTest
+ * @summary check jaotc can compile class
+ */
+
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldOne;
+import java.io.File;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class CompileClassTest {
+ public static void main(String[] args) {
+ OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--class-name", JaotcTestHelper
+ .getClassAotCompilationName(HelloWorldOne.class));
+ oa.shouldHaveExitValue(0);
+ File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+ Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing");
+ Asserts.assertGT(compiledLibrary.length(), 0L, "Unexpected compiled library size");
+ JaotcTestHelper.checkLibraryUsage(HelloWorldOne.class.getName());
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileClassWithDebugTest.java b/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileClassWithDebugTest.java
new file mode 100644
index 000000000..7681a9dfe
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileClassWithDebugTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.cli.jaotc.CompileClassWithDebugTest
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
+ * @run driver compiler.aot.cli.jaotc.CompileClassWithDebugTest
+ * @summary check that jaotc can compile a class with a --debug flag
+ */
+
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldOne;
+import java.io.File;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class CompileClassWithDebugTest {
+ public static void main(String[] args) {
+ OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--debug", "--class-name", JaotcTestHelper
+ .getClassAotCompilationName(HelloWorldOne.class));
+ oa.shouldHaveExitValue(0);
+ File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+ Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing");
+ Asserts.assertGT(compiledLibrary.length(), 0L, "Unexpected compiled library size");
+ JaotcTestHelper.checkLibraryUsage(HelloWorldOne.class.getName());
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileDirectoryTest.java b/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileDirectoryTest.java
new file mode 100644
index 000000000..cb02909a8
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileDirectoryTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.cli.jaotc.CompileDirectoryTest
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
+ * compiler.aot.cli.jaotc.data.HelloWorldTwo
+ * @run driver compiler.aot.cli.jaotc.CompileDirectoryTest
+ * @summary check jaotc can compile directory with classes where directory is specified by relative path
+ */
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldOne;
+import compiler.aot.cli.jaotc.data.HelloWorldTwo;
+import java.io.File;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class CompileDirectoryTest {
+ public static void main(String[] args) {
+ OutputAnalyzer oa =JaotcTestHelper.compileLibrary("--directory", ".");
+ oa.shouldHaveExitValue(0);
+ File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+ Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing");
+ Asserts.assertGT(compiledLibrary.length(), 0L, "Unexpected compiled library size");
+ JaotcTestHelper.checkLibraryUsage(HelloWorldOne.class.getName());
+ JaotcTestHelper.checkLibraryUsage(HelloWorldTwo.class.getName());
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileJarTest.java b/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileJarTest.java
new file mode 100644
index 000000000..2868bf463
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileJarTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.cli.jaotc.CompileJarTest
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
+ * compiler.aot.cli.jaotc.data.HelloWorldTwo
+ * @run driver compiler.aot.cli.jaotc.CompileJarTest
+ * @summary check jaotc can compile jar
+ */
+
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldOne;
+import compiler.aot.cli.jaotc.data.HelloWorldTwo;
+import java.io.File;
+import java.io.IOException;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.JDKToolLauncher;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class CompileJarTest {
+ private static final String JAR_NAME = "test.jar";
+
+ public static void main(String[] args) {
+ createJar();
+ OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--jar", JAR_NAME);
+ oa.shouldHaveExitValue(0);
+ File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+ Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing");
+ Asserts.assertGT(compiledLibrary.length(), 0L, "Unexpected compiled library size");
+ JaotcTestHelper.checkLibraryUsage(HelloWorldOne.class.getName());
+ JaotcTestHelper.checkLibraryUsage(HelloWorldTwo.class.getName());
+ }
+
+ private static void createJar() {
+ JDKToolLauncher jar = JDKToolLauncher.create("jar")
+ .addToolArg("-cf")
+ .addToolArg(JAR_NAME)
+ .addToolArg("-C")
+ .addToolArg(".")
+ .addToolArg(".");
+ OutputAnalyzer oa;
+ try {
+ oa = new OutputAnalyzer(new ProcessBuilder(jar.getCommand()).start());
+ } catch (IOException e) {
+ throw new Error("Problems launching jar: " + e, e);
+ }
+ oa.shouldHaveExitValue(0);
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileModuleTest.java b/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileModuleTest.java
new file mode 100644
index 000000000..c33b8d7c7
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/jaotc/CompileModuleTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @run driver compiler.aot.cli.jaotc.CompileModuleTest
+ * @summary check jaotc can compile module
+ */
+
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldTwo;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Arrays;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class CompileModuleTest {
+ private static final String TESTED_CLASS_NAME = HelloWorldTwo.class.getName();
+ private static final String STRING_LENGTH = String.class.getName() + ".length";
+ private static final String COMPILE_COMMAND = "compileOnly " + STRING_LENGTH + ".*";
+ private static final Path COMPILE_COMMAND_FILE = Paths.get("stringLengthOnly.list");
+ private static final String[] EXPECTED = new String[]{
+ JaotcTestHelper.DEFAULT_LIBRARY_LOAD_MESSAGE,
+ STRING_LENGTH
+ };
+ private static final String[] UNEXPECTED = new String[]{
+ TESTED_CLASS_NAME
+ };
+
+ public static void main(String[] args) {
+ // compile only java.lang.String::length from java.base module to have reasonable compilation time
+ try {
+ Files.write(COMPILE_COMMAND_FILE, Arrays.asList(COMPILE_COMMAND),
+ StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW);
+ } catch (IOException e) {
+ throw new Error("TESTBUG: can't write list file " + e, e);
+ }
+ OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--compile-commands",
+ COMPILE_COMMAND_FILE.toString(), "--module", "java.base");
+ oa.shouldHaveExitValue(0);
+ File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+ Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing");
+ Asserts.assertGT(compiledLibrary.length(), 0L, "Unexpected compiled library size");
+ JaotcTestHelper.checkLibraryUsage(TESTED_CLASS_NAME, EXPECTED, UNEXPECTED);
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/jaotc/IgnoreErrorsTest.java b/test/hotspot/jtreg/compiler/aot/cli/jaotc/IgnoreErrorsTest.java
new file mode 100644
index 000000000..ac0eb233d
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/jaotc/IgnoreErrorsTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library / /test/lib /testlibrary
+ * @compile IllegalClass.jasm
+ * @run driver/timeout=360 compiler.aot.cli.jaotc.IgnoreErrorsTest
+ */
+
+package compiler.aot.cli.jaotc;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class IgnoreErrorsTest {
+ public static void main(String[] args) {
+ try {
+ Files.write(Paths.get("Empty.class"), new byte[] { }, StandardOpenOption.CREATE_NEW);
+ } catch (IOException e) {
+ throw new Error("can't create empty class file", e);
+ }
+ File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+ OutputAnalyzer oa;
+
+ System.out.println("Compiling empty class file w/o --ignore-errors");
+ oa = JaotcTestHelper.compileLibrary(
+ "--class-name", "Empty",
+ "--class-name", "java.lang.Object");
+ oa.shouldNotHaveExitValue(0);
+ Asserts.assertTrue(!compiledLibrary.exists(), "Compiled library file exists");
+
+ System.out.println("Compiling empty class file w/ --ignore-errors");
+ oa = JaotcTestHelper.compileLibrary(
+ "--ignore-errors",
+ "--class-name", "Empty",
+ "--class-name", "java.lang.Object");
+ oa.shouldHaveExitValue(0);
+ Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file is missed");
+ JaotcTestHelper.checkLibraryUsage("-version");
+ compiledLibrary.delete();
+
+ System.out.println("Compiling illegal class file w/o --ignore-errors");
+ oa = JaotcTestHelper.compileLibrary(
+ "--class-name", "IllegalClass",
+ "--class-name", "java.lang.Object");
+ oa.shouldNotHaveExitValue(0);
+ Asserts.assertTrue(!compiledLibrary.exists(), "Compiled library file exists");
+
+ System.out.println("Compiling illegal class file w/ --ignore-errors");
+ oa = JaotcTestHelper.compileLibrary(
+ "--ignore-errors",
+ "--class-name", "IllegalClass",
+ "--class-name", "java.lang.Object");
+ oa.shouldHaveExitValue(0);
+ Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file is missed");
+ JaotcTestHelper.checkLibraryUsage("-version");
+ compiledLibrary.delete();
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/jaotc/IllegalClass.jasm b/test/hotspot/jtreg/compiler/aot/cli/jaotc/IllegalClass.jasm
new file mode 100644
index 000000000..1aa0057df
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/jaotc/IllegalClass.jasm
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+super public class IllegalClass
+ extends java/lang/String
+ version 46:0
+{ }
diff --git a/test/hotspot/jtreg/compiler/aot/cli/jaotc/JaotcTestHelper.java b/test/hotspot/jtreg/compiler/aot/cli/jaotc/JaotcTestHelper.java
new file mode 100644
index 000000000..ee85d3278
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/jaotc/JaotcTestHelper.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.AotCompiler;
+
+import java.io.File;
+import java.io.IOException;
+
+import jdk.test.lib.process.ExitCode;
+import jdk.test.lib.Platform;
+import jdk.test.lib.JDKToolLauncher;
+import jdk.test.lib.Utils;
+import jdk.test.lib.cli.CommandLineOptionTest;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+public class JaotcTestHelper {
+ public static final String DEFAULT_LIB_PATH = "./unnamed." + Platform.sharedLibraryExt();
+ public static final String DEFAULT_LIBRARY_LOAD_MESSAGE = "loaded " + DEFAULT_LIB_PATH
+ + " aot library";
+ private static final String UNLOCK_EXPERIMENTAL_VM_OPTIONS = "-XX:+UnlockExperimentalVMOptions";
+ private static final String ENABLE_AOT = "-XX:+UseAOT";
+ private static final String AOT_LIBRARY = "-XX:AOTLibrary=" + DEFAULT_LIB_PATH;
+ private static final String PRINT_AOT = "-XX:+PrintAOT";
+
+ public static OutputAnalyzer compileLibrary(String... args) {
+ JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jaotc");
+ for (String vmOpt : Utils.getTestJavaOpts()) {
+ launcher.addVMArg(vmOpt);
+ }
+ launcher.addToolArg("--compile-with-assertions");
+ for (String arg : args) {
+ launcher.addToolArg(arg);
+ }
+ String linker = AotCompiler.resolveLinker();
+ if (linker != null) {
+ launcher.addToolArg("--linker-path");
+ launcher.addToolArg(linker);
+ }
+ String[] cmd = launcher.getCommand();
+ try {
+ return ProcessTools.executeCommand(cmd);
+ } catch (Throwable e) {
+ throw new Error("Can't start test process: " + e, e);
+ }
+ }
+
+ public static void checkLibraryUsage(String classToRun) {
+ checkLibraryUsage(classToRun, new String[]{DEFAULT_LIBRARY_LOAD_MESSAGE}, null);
+ }
+
+ public static void checkLibraryUsage(String classToRun, String[] expectedOutput,
+ String[] unexpectedOutput) {
+ try {
+ CommandLineOptionTest.verifyJVMStartup(expectedOutput, unexpectedOutput,
+ "Unexpected exit code", "Unexpected output", ExitCode.OK,
+ /* addTestVMOpts */ true, UNLOCK_EXPERIMENTAL_VM_OPTIONS,
+ ENABLE_AOT, AOT_LIBRARY, PRINT_AOT, classToRun);
+ } catch (Throwable t) {
+ throw new Error("Library usage verification failed: " + t, t);
+ }
+ }
+
+ public static String getClassAotCompilationFilename(Class<?> classToCompile) {
+ return classToCompile.getName().replaceAll("\\.","/") + ".class";
+ }
+
+ public static String getClassAotCompilationName(Class<?> classToCompile) {
+ return classToCompile.getName();
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/jaotc/ListOptionNotExistingTest.java b/test/hotspot/jtreg/compiler/aot/cli/jaotc/ListOptionNotExistingTest.java
new file mode 100644
index 000000000..0eb3e1916
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/jaotc/ListOptionNotExistingTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.cli.jaotc.ListOptionNotExistingTest
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
+ * @run driver compiler.aot.cli.jaotc.ListOptionNotExistingTest
+ * @summary check jaotc can handle situation with missing --compile-commands file
+ */
+
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldOne;
+import java.io.File;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class ListOptionNotExistingTest {
+ private static final String COMPILE_ITEM
+ = JaotcTestHelper.getClassAotCompilationName(HelloWorldOne.class);
+
+ public static void main(String[] args) {
+ OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--compile-commands", "./notExisting.list",
+ "--class-name", COMPILE_ITEM);
+ int exitCode = oa.getExitValue();
+ Asserts.assertNE(exitCode, 0, "Unexpected compilation exit code");
+ File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+ Asserts.assertFalse(compiledLibrary.exists(), "Compiler library unexpectedly exists");
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/jaotc/ListOptionTest.java b/test/hotspot/jtreg/compiler/aot/cli/jaotc/ListOptionTest.java
new file mode 100644
index 000000000..8bf2fcf98
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/jaotc/ListOptionTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.cli.jaotc.ListOptionTest
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
+ * @run driver compiler.aot.cli.jaotc.ListOptionTest
+ * @summary check jaotc can use --compile-commands option successfully and respective compileCommand is applied
+ */
+
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldOne;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Arrays;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class ListOptionTest {
+ private static final String TESTED_CLASS_NAME = HelloWorldOne.class.getName();
+ private static final String HELLOWORLDONE_MAIN = TESTED_CLASS_NAME + ".main";
+ private static final String COMPILE_COMMAND = "compileOnly " + HELLOWORLDONE_MAIN + ".*";
+ private static final Path COMPILE_COMMAND_FILE = Paths.get("helloWorldMainMethodOnly.list");
+ private static final String[] EXPECTED = new String[]{
+ JaotcTestHelper.DEFAULT_LIBRARY_LOAD_MESSAGE,
+ TESTED_CLASS_NAME + ".main"
+ };
+ private static final String[] UNEXPECTED = new String[]{
+ TESTED_CLASS_NAME + ".<init>"
+ };
+
+ public static void main(String[] args) {
+ try {
+ Files.write(COMPILE_COMMAND_FILE, Arrays.asList(COMPILE_COMMAND),
+ StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW);
+ } catch (IOException e) {
+ throw new Error("TESTBUG: can't write list file " + e, e);
+ }
+ OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--compile-commands", COMPILE_COMMAND_FILE.toString(),
+ "--class-name", JaotcTestHelper.getClassAotCompilationName(HelloWorldOne.class));
+ oa.shouldHaveExitValue(0);
+ File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+ Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing");
+ Asserts.assertGT(compiledLibrary.length(), 0L, "Unexpected compiled library size");
+ JaotcTestHelper.checkLibraryUsage(TESTED_CLASS_NAME, EXPECTED, UNEXPECTED);
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/jaotc/ListOptionWrongFileTest.java b/test/hotspot/jtreg/compiler/aot/cli/jaotc/ListOptionWrongFileTest.java
new file mode 100644
index 000000000..0f1df8e12
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/jaotc/ListOptionWrongFileTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.cli.jaotc.ListOptionWrongFileTest
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
+ * @run driver compiler.aot.cli.jaotc.ListOptionWrongFileTest
+ * @summary check jaotc can handle incorrect --compile-commands file
+ */
+
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldOne;
+import java.io.File;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class ListOptionWrongFileTest {
+ private static final String TESTED_CLASS_NAME = HelloWorldOne.class.getName();
+ private static final String[] EXPECTED = new String[]{
+ JaotcTestHelper.DEFAULT_LIBRARY_LOAD_MESSAGE,
+ TESTED_CLASS_NAME
+ };
+
+ private static final String COMPILE_ITEM
+ = JaotcTestHelper.getClassAotCompilationName(HelloWorldOne.class);
+
+ private static final String COMPILE_FILE
+ = JaotcTestHelper.getClassAotCompilationFilename(HelloWorldOne.class);
+
+ public static void main(String[] args) {
+ // expecting wrong file to be read but no compilation directive recognized, so, all compiled
+ OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--compile-commands", COMPILE_FILE, "--class-name", COMPILE_ITEM);
+ oa.shouldHaveExitValue(0);
+ File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+ Asserts.assertTrue(compiledLibrary.exists(), "Expected compiler library to exist");
+ JaotcTestHelper.checkLibraryUsage(HelloWorldOne.class.getName(), EXPECTED, null);
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/jaotc/data/HelloWorldOne.java b/test/hotspot/jtreg/compiler/aot/cli/jaotc/data/HelloWorldOne.java
new file mode 100644
index 000000000..8a1d727b1
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/jaotc/data/HelloWorldOne.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot.cli.jaotc.data;
+
+public class HelloWorldOne {
+ public static final String MESSAGE = "HelloWorld1";
+
+ public static void main(String args[]) {
+ System.out.println(MESSAGE);
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/cli/jaotc/data/HelloWorldTwo.java b/test/hotspot/jtreg/compiler/aot/cli/jaotc/data/HelloWorldTwo.java
new file mode 100644
index 000000000..dce2b2902
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/cli/jaotc/data/HelloWorldTwo.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot.cli.jaotc.data;
+
+public class HelloWorldTwo {
+ public static final String MESSAGE = "HelloWorld2";
+
+ public static void main(String args[]) {
+ System.out.println(MESSAGE);
+ System.out.println("Message length = " + MESSAGE.length());
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/fingerprint/CDSDumper.java b/test/hotspot/jtreg/compiler/aot/fingerprint/CDSDumper.java
new file mode 100644
index 000000000..af1700419
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/fingerprint/CDSDumper.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot.fingerprint;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+// Usage:
+// java CDSDumper <classpath> <classlist> <archive> <heapsize> <class1> <class2> ...
+public class CDSDumper {
+ public static void main(String[] args) throws Exception {
+ String classpath = args[0];
+ String classlist = args[1];
+ String archive = args[2];
+ String heapsize = args[3];
+
+ // Prepare the classlist
+ FileOutputStream fos = new FileOutputStream(classlist);
+ PrintStream ps = new PrintStream(fos);
+
+ for (int i=4; i<args.length; i++) {
+ ps.println(args[i].replace('.', '/'));
+ }
+ ps.close();
+ fos.close();
+
+ // Dump the archive
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ heapsize,
+ "-XX:+IgnoreUnrecognizedVMOptions",
+ "-cp", classpath,
+ "-XX:ExtraSharedClassListFile=" + classlist,
+ "-XX:SharedArchiveFile=" + archive,
+ "-Xshare:dump",
+ "-Xlog:gc+heap+coops",
+ "-Xlog:cds");
+
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ System.out.println("[stdout = " + output.getStdout() + "]");
+ System.out.println("[stderr = " + output.getStderr() + "]");
+ output.shouldContain("Loading classes to share");
+ output.shouldHaveExitValue(0);
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/fingerprint/CDSRunner.java b/test/hotspot/jtreg/compiler/aot/fingerprint/CDSRunner.java
new file mode 100644
index 000000000..3b45cff8d
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/fingerprint/CDSRunner.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot.fingerprint;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+// Usage:
+// java CDSRunner <vmargs> <class> <args> ...
+public class CDSRunner {
+ public static void main(String[] args) throws Exception {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args);
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+ System.out.println("[stdout = " + output.getStdout() + "]");
+ System.out.println("[stderr = " + output.getStderr() + "]");
+
+ output.shouldContain("PASSED");
+ output.shouldHaveExitValue(0);
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/fingerprint/SelfChanged.java b/test/hotspot/jtreg/compiler/aot/fingerprint/SelfChanged.java
new file mode 100644
index 000000000..bde477836
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/fingerprint/SelfChanged.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary AOT methods should be swept if a super class has changed.
+ * @library /test/lib /
+ * @modules java.base/jdk.internal.misc
+ * java.management
+ * @requires vm.aot
+ * @build compiler.aot.fingerprint.SelfChanged
+ * compiler.aot.AotCompiler
+ *
+ * @run main
+ * compiler.aot.fingerprint.SelfChanged WRITE-UNMODIFIED-CLASS
+ * @run driver compiler.aot.AotCompiler -libname libSelfChanged.so
+ * -class compiler.aot.fingerprint.Blah
+ *
+ * @run main/othervm
+ * compiler.aot.fingerprint.SelfChanged TEST-UNMODIFIED
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT -XX:+PrintAOT
+ * -XX:AOTLibrary=./libSelfChanged.so
+ * -Xlog:aot+class+fingerprint=trace -Xlog:aot+class+load=trace
+ * compiler.aot.fingerprint.SelfChanged TEST-UNMODIFIED
+ *
+ * @run main
+ * compiler.aot.fingerprint.SelfChanged WRITE-MODIFIED-CLASS
+ * @run main
+ * compiler.aot.fingerprint.SelfChanged TEST-MODIFIED
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT -XX:+PrintAOT
+ * -XX:AOTLibrary=./libSelfChanged.so
+ * -Xlog:aot+class+fingerprint=trace -Xlog:aot+class+load=trace
+ * compiler.aot.fingerprint.SelfChanged TEST-MODIFIED
+ */
+
+package compiler.aot.fingerprint;
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.compiler.InMemoryJavaCompiler;
+
+import java.io.*;
+
+class Blah {
+ volatile int z;
+ int getX() {
+ for (z = 0; z < 10000; z++) {
+ if (z % 7 == 1) {
+ z += 2;
+ }
+ }
+ return 0;
+ }
+}
+
+public class SelfChanged {
+ public static void main(String args[]) throws Throwable {
+ Blah f = new Blah();
+ System.out.println("f.getX = " + f.getX());
+ switch (args[0]) {
+ case "WRITE-UNMODIFIED-CLASS":
+ compileClass(false);
+ break;
+ case "WRITE-MODIFIED-CLASS":
+ compileClass(true);
+ break;
+ case "TEST-UNMODIFIED":
+ Asserts.assertTrue(f.getX() == 0, "getX from unmodified Blah class should return 0");
+ break;
+ case "TEST-MODIFIED":
+ Asserts.assertTrue(f.getX() == 1, "getX from modified Blah class should return 1");
+ break;
+ default:
+ throw new RuntimeException("unexpected option: " + args[0]);
+ }
+ }
+
+ static void compileClass(boolean isModified) throws Throwable {
+ String src =
+ "package compiler.aot.fingerprint;"
+ + "public class Blah {"
+ + " volatile int z;"
+ + " int getX() {"
+ + " for (z = 0; z < 10000; z++) {"
+ + " if (z % 7 == 1) {"
+ + " z += 2;"
+ + " }"
+ + " }"
+ + " return " + ((isModified) ? "1" : "0") + ";"
+ + " }"
+ + " int getY() {return 255;}"
+
+ // The following is for the SelfChangedCDS.java test case. We always load an unmodified
+ // version of Blah from the CDS archive. However, we would load an AOT library that
+ // was compiled using a modified version of Blah. The getX method in this AOT library should
+ // not be used.
+
+ + " public static void main(String args[]) {"
+ + " Blah b = new Blah();"
+ + " int n = b.getX();"
+ + " if (n != 0) {"
+ + " throw new RuntimeException(args[0] + \" : \" + n);"
+ + " }"
+ + " System.out.println(\"PASSED\");"
+ + " }"
+ + "}";
+
+ String filename = System.getProperty("test.classes") + "/compiler/aot/fingerprint/Blah.class";
+ FileOutputStream fos = new FileOutputStream(filename);
+ fos.write(InMemoryJavaCompiler.compile("compiler.aot.fingerprint.Blah", src));
+ fos.close();
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/fingerprint/SelfChangedCDS.java b/test/hotspot/jtreg/compiler/aot/fingerprint/SelfChangedCDS.java
new file mode 100644
index 000000000..7463ab0c9
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/fingerprint/SelfChangedCDS.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary AOT methods should be swept if a super class has changed (with CDS).
+ * @library /test/lib /
+ * @modules java.base/jdk.internal.misc
+ * java.management
+ * @requires vm.aot & vm.cds
+ * @build compiler.aot.fingerprint.SelfChanged
+ * jdk.test.whitebox.WhiteBox
+ *
+ * @run driver compiler.aot.fingerprint.SelfChanged WRITE-UNMODIFIED-CLASS
+ * @run driver compiler.aot.AotCompiler -libname libSelfChanged.so
+ * -class compiler.aot.fingerprint.Blah
+ *
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar SelfChangedCDS.jar compiler.aot.fingerprint.Blah
+ * @run driver compiler.aot.fingerprint.CDSDumper SelfChangedCDS.jar SelfChangedCDS.classlist SelfChangedCDS.jsa -showversion
+ * compiler.aot.fingerprint.Blah
+ *
+ * @run driver compiler.aot.fingerprint.CDSRunner -cp SelfChangedCDS.jar
+ * compiler.aot.fingerprint.Blah TEST-UNMODIFIED
+ * @run driver compiler.aot.fingerprint.CDSRunner -cp SelfChangedCDS.jar
+ * -XX:+UnlockExperimentalVMOptions -XX:+UseAOT -XX:+PrintAOT
+ * -XX:AOTLibrary=./libSelfChanged.so
+ * -XX:SharedArchiveFile=SelfChangedCDS.jsa
+ * -XX:+IgnoreUnrecognizedVMOptions
+ * -Xshare:auto -showversion
+ * -Xlog:cds -Xlog:gc+heap+coops
+ * -Xlog:aot+class+fingerprint=trace -Xlog:aot+class+load=trace
+ * compiler.aot.fingerprint.Blah TEST-UNMODIFIED
+ *
+ * @run driver
+ * compiler.aot.fingerprint.SelfChanged WRITE-MODIFIED-CLASS
+ * @run driver compiler.aot.AotCompiler -libname libSelfChanged.so
+ * -class compiler.aot.fingerprint.Blah
+ *
+ * @run driver compiler.aot.fingerprint.CDSRunner -cp SelfChangedCDS.jar
+ * compiler.aot.fingerprint.Blah TEST-MODIFIED
+ * @run driver compiler.aot.fingerprint.CDSRunner -cp SelfChangedCDS.jar
+ * -XX:+UnlockExperimentalVMOptions -XX:+UseAOT -XX:+PrintAOT
+ * -XX:AOTLibrary=./libSelfChanged.so
+ * -XX:SharedArchiveFile=SelfChangedCDS.jsa
+ * -XX:+IgnoreUnrecognizedVMOptions
+ * -Xshare:auto -showversion
+ * -Xlog:cds -Xlog:gc+heap+coops
+ * -Xlog:aot+class+fingerprint=trace -Xlog:aot+class+load=trace
+ * compiler.aot.fingerprint.Blah TEST-MODIFIED
+ *
+ *
+ * @run driver compiler.aot.AotCompiler -libname libSelfChanged.so
+ * -class compiler.aot.fingerprint.Blah
+ * -extraopt -Xmx512m
+ *
+ * @run driver compiler.aot.fingerprint.CDSDumper SelfChangedCDS.jar SelfChangedCDS.classlist SelfChangedCDS.jsa -Xmx512m
+ * compiler.aot.fingerprint.Blah
+ *
+ * @run driver compiler.aot.fingerprint.CDSRunner -Xmx512m -cp SelfChangedCDS.jar
+ * compiler.aot.fingerprint.Blah TEST-UNMODIFIED
+ * @run driver compiler.aot.fingerprint.CDSRunner -Xmx512m -cp SelfChangedCDS.jar
+ * -XX:+UnlockExperimentalVMOptions -XX:+UseAOT -XX:+PrintAOT
+ * -XX:AOTLibrary=./libSelfChanged.so
+ * -XX:SharedArchiveFile=SelfChangedCDS.jsa
+ * -XX:+IgnoreUnrecognizedVMOptions
+ * -Xshare:auto -showversion
+ * -Xlog:cds -Xlog:gc+heap+coops
+ * -Xlog:aot+class+fingerprint=trace -Xlog:aot+class+load=trace
+ * compiler.aot.fingerprint.Blah TEST-UNMODIFIED
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/fingerprint/SuperChanged.java b/test/hotspot/jtreg/compiler/aot/fingerprint/SuperChanged.java
new file mode 100644
index 000000000..fa4bd84e7
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/fingerprint/SuperChanged.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary AOT methods should be swept if a super class has changed.
+ * @library /test/lib /
+ * @modules java.base/jdk.internal.misc
+ * java.management
+ * @requires vm.aot
+ * @build compiler.aot.fingerprint.SuperChanged
+ * compiler.aot.AotCompiler
+ *
+ * @run main
+ * compiler.aot.fingerprint.SuperChanged WRITE-UNMODIFIED-CLASS
+ * @run driver compiler.aot.AotCompiler -libname libSuperChanged.so
+ * -class compiler.aot.fingerprint.Foo
+ *
+ * @run main
+ * compiler.aot.fingerprint.SuperChanged TEST-UNMODIFIED
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT -XX:+PrintAOT
+ * -XX:AOTLibrary=./libSuperChanged.so
+ * -Xlog:aot+class+fingerprint=trace -Xlog:aot+class+load=trace
+ * compiler.aot.fingerprint.SuperChanged TEST-UNMODIFIED
+ *
+ * @run main
+ * compiler.aot.fingerprint.SuperChanged WRITE-MODIFIED-CLASS
+ * @run main
+ * compiler.aot.fingerprint.SuperChanged TEST-MODIFIED
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseAOT -XX:+PrintAOT
+ * -XX:AOTLibrary=./libSuperChanged.so
+ * -Xlog:aot+class+fingerprint=trace -Xlog:aot+class+load=trace
+ * compiler.aot.fingerprint.SuperChanged TEST-MODIFIED
+ */
+
+package compiler.aot.fingerprint;
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.compiler.InMemoryJavaCompiler;
+
+import java.io.*;
+
+class Bar {
+ volatile int x = 0;
+ volatile int y = 1;
+}
+
+class Foo extends Bar {
+
+ volatile int z;
+ int getX() {
+ for (z = 0; z < 10000; z++) {
+ if (z % 7 == 1) {
+ z += 2;
+ }
+ }
+ return x;
+ }
+}
+
+public class SuperChanged {
+ public static void main(String args[]) throws Throwable {
+ Foo f = new Foo();
+ System.out.println("f.getX = " + f.getX());
+ switch (args[0]) {
+ case "WRITE-UNMODIFIED-CLASS":
+ compileClass(false);
+ break;
+ case "WRITE-MODIFIED-CLASS":
+ compileClass(true);
+ break;
+ case "TEST-UNMODIFIED":
+ Asserts.assertTrue(f.getX() == 0, "getX from unmodified Foo class should return 0");
+ break;
+ case "TEST-MODIFIED":
+ Asserts.assertTrue(f.getX() == 1, "getX from modified Foo class should return 1");
+ break;
+ default:
+ throw new RuntimeException("unexpected option: " + args[0]);
+ }
+ }
+
+ static void compileClass(boolean isModified) throws Throwable {
+ String class_src_0 = "package compiler.aot.fingerprint; class Bar {volatile int x = 0; volatile int y = 1;}";
+ String class_src_1 = "package compiler.aot.fingerprint; class Bar {volatile int y = 0; volatile int x = 1;}";
+ String src = (isModified) ? class_src_1 : class_src_0;
+
+ String filename = System.getProperty("test.classes") + "/compiler/aot/fingerprint/Bar.class";
+ FileOutputStream fos = new FileOutputStream(filename);
+ fos.write(InMemoryJavaCompiler.compile("compiler.aot.fingerprint.Bar", src));
+ fos.close();
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/NativeOrderOutputStreamTest.java b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/NativeOrderOutputStreamTest.java
new file mode 100644
index 000000000..9304a8e42
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/NativeOrderOutputStreamTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @requires vm.aot
+ * @modules jdk.aot/jdk.tools.jaotc.utils
+ * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.tools.jaotc.test.NativeOrderOutputStreamTest
+ */
+
+package jdk.tools.jaotc.test;
+
+import jdk.tools.jaotc.utils.NativeOrderOutputStream;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class NativeOrderOutputStreamTest {
+
+ private NativeOrderOutputStream target;
+
+ @Before
+ public void setup() {
+ target = new NativeOrderOutputStream();
+ }
+
+ @Test
+ public void shouldAdd4BytesForInt() {
+ target.putInt(5);
+ Assert.assertEquals(4, target.position());
+ }
+
+ @Test
+ public void shouldAdd8BytesForLong() {
+ target.putLong(8);
+ Assert.assertEquals(8, target.position());
+ }
+
+ @Test
+ public void shouldHaveCorrectSizeBeforePatch() {
+ target.patchableInt();
+ Assert.assertEquals(4, target.position());
+ }
+
+ @Test
+ public void shouldHaveCorrectSizeAfterPatch() {
+ NativeOrderOutputStream.PatchableInt patchableInt = target.patchableInt();
+ patchableInt.set(12);
+ Assert.assertEquals(4, target.position());
+ }
+
+ @Test
+ public void shouldSetCorrectValueInPatch() {
+ NativeOrderOutputStream.PatchableInt patchableInt = target.patchableInt();
+ patchableInt.set(42);
+ Assert.assertEquals(42, getInt(0));
+ }
+
+ private int getInt(int pos) {
+ ByteBuffer buffer = ByteBuffer.wrap(target.array());
+ buffer.order(ByteOrder.nativeOrder());
+ return buffer.getInt(pos);
+ }
+
+ @Test
+ public void shouldPutArrayCorrectly() {
+ target.put(new byte[]{42, 5, 43, 44});
+ Assert.assertEquals(4, target.position());
+ Assert.assertEquals(42, target.array()[0]);
+ Assert.assertEquals(4, target.position());
+ }
+
+ @Test
+ public void shouldOnlyPatchSlot() {
+ NativeOrderOutputStream.PatchableInt patchableInt = target.patchableInt();
+ target.putInt(7);
+ patchableInt.set(39);
+ Assert.assertEquals(39, getInt(0));
+ Assert.assertEquals(7, getInt(4));
+ }
+
+ @Test
+ public void shouldBeAbleToPatchAnywhere() {
+ target.putInt(19);
+ NativeOrderOutputStream.PatchableInt patchableInt = target.patchableInt();
+ patchableInt.set(242);
+
+ Assert.assertEquals(19, getInt(0));
+ Assert.assertEquals(242, getInt(4));
+ }
+
+ @Test
+ public void shouldHavePatchableAtRightOffset() {
+ target.putInt(27);
+ Assert.assertEquals(4, target.position());
+ NativeOrderOutputStream.PatchableInt patchableInt = target.patchableInt();
+ Assert.assertEquals(4, patchableInt.position());
+ }
+
+ @Test
+ public void shouldAlign() {
+ target.putInt(9);
+ target.align(16);
+ target.put(new byte[]{3});
+ target.align(8);
+ Assert.assertEquals(24, target.position());
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java
new file mode 100644
index 000000000..9a6de1a19
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @requires vm.aot
+ * @modules jdk.aot/jdk.tools.jaotc
+ * jdk.aot/jdk.tools.jaotc.collect
+ * @run junit/othervm jdk.tools.jaotc.test.collect.ClassSearchTest
+ */
+
+package jdk.tools.jaotc.test.collect;
+
+
+import jdk.tools.jaotc.LoadedClass;
+import jdk.tools.jaotc.collect.*;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+
+public class ClassSearchTest {
+ @Test(expected = InternalError.class)
+ public void itShouldThrowExceptionIfNoProvidersAvailable() {
+ ClassSearch target = new ClassSearch();
+ SearchPath searchPath = new SearchPath();
+ target.search(list(new SearchFor("foo")), searchPath);
+ }
+
+ @Test
+ public void itShouldFindAProviderForEachEntry() {
+ Set<String> searched = new HashSet<>();
+ ClassSearch target = new ClassSearch();
+ target.addProvider(provider("", (name, searchPath) -> {
+ searched.add(name);
+ return new NoopSource();
+ }));
+ target.search(searchForList("foo", "bar", "foobar"), null);
+ Assert.assertEquals(hashset("foo", "bar", "foobar"), searched);
+ }
+
+ private SourceProvider provider(String supports, BiFunction<String, SearchPath, ClassSource> fn) {
+ return new SourceProvider() {
+ @Override
+ public ClassSource findSource(String name, SearchPath searchPath) {
+ return fn.apply(name, searchPath);
+ }
+
+ @Override
+ public boolean supports(String type) {
+ return supports.equals(type);
+ }
+ };
+ }
+
+ @Test
+ public void itShouldOnlySearchSupportedProvidersForKnownType() {
+ Set<String> visited = new HashSet<>();
+ ClassSearch target = new ClassSearch();
+
+ target.addProvider(provider("jar", (name, searchPath) -> {
+ visited.add("jar");
+ return null;
+ }));
+
+ target.addProvider(provider("dir", (name, searchPath) -> {
+ visited.add("dir");
+ return null;
+ }));
+
+ try {
+ target.search(list(new SearchFor("some", "dir")), null);
+ } catch (InternalError e) {
+ // throws because no provider gives a source
+ }
+
+ Assert.assertEquals(hashset("dir"), visited);
+ }
+
+ @Test(expected = InternalError.class)
+ public void itShouldThrowErrorIfMultipleSourcesAreAvailable() {
+ ClassSearch target = new ClassSearch();
+ target.addProvider(provider("", (name, searchPath) -> consumer -> Assert.fail()));
+ target.addProvider(provider("", (name, searchPath) -> consumer -> Assert.fail()));
+
+ target.search(searchForList("somethign"), null);
+ }
+
+ @Test
+ public void itShouldSearchAllProvidersForUnknownType() {
+ Set<String> visited = new HashSet<>();
+ ClassSearch target = new ClassSearch();
+ target.addProvider(provider("", (name, searchPath) -> {
+ visited.add("1");
+ return null;
+ }));
+ target.addProvider(provider("", (name, searchPath) -> {
+ visited.add("2");
+ return null;
+ }));
+
+ try {
+ target.search(searchForList("foo"), null);
+ } catch (InternalError e) {
+ // throws because no provider gives a source
+ }
+
+ Assert.assertEquals(hashset("1", "2"), visited);
+ }
+
+ @Test
+ public void itShouldTryToLoadSaidClassFromClassLoader() {
+ Set<String> loaded = new HashSet<>();
+
+ ClassSearch target = new ClassSearch();
+ target.addProvider(new SourceProvider() {
+ @Override
+ public boolean supports(String type) {
+ return true;
+ }
+
+ @Override
+ public ClassSource findSource(String name, SearchPath searchPath) {
+ return new ClassSource() {
+ @Override
+ public void eachClass(BiConsumer<String, ClassLoader> consumer) {
+ consumer.accept("foo.Bar", new ClassLoader() {
+ @Override
+ public Class<?> loadClass(String name) throws ClassNotFoundException {
+ loaded.add(name);
+ return null;
+ }
+ });
+ }
+ };
+ }
+ });
+
+ java.util.List<LoadedClass> search = target.search(searchForList("/tmp/something"), null);
+ Assert.assertEquals(list(new LoadedClass("foo.Bar", null)), search);
+ }
+
+ @Test(expected = InternalError.class)
+ public void itShouldThrowInternalErrorWhenClassLoaderFails() {
+ ClassLoader classLoader = new ClassLoader() {
+ @Override
+ public Class<?> loadClass(String name1) throws ClassNotFoundException {
+ throw new ClassNotFoundException("failed to find " + name1);
+ }
+ };
+
+ ClassSearch target = new ClassSearch();
+ target.addProvider(provider("", (name, searchPath) -> consumer -> consumer.accept("foo.Bar", classLoader)));
+ target.search(searchForList("foobar"), null);
+ }
+
+ private List<SearchFor> searchForList(String... entries) {
+ List<SearchFor> list = new ArrayList<>();
+ for (String entry : entries) {
+ list.add(new SearchFor(entry));
+ }
+ return list;
+ }
+
+ private <T> List<T> list(T... entries) {
+ List<T> list = new ArrayList<T>();
+ for (T entry : entries) {
+ list.add(entry);
+ }
+ return list;
+ }
+
+ private <T> Set<T> hashset(T... entries) {
+ Set<T> set = new HashSet<T>();
+ for (T entry : entries) {
+ set.add(entry);
+ }
+ return set;
+ }
+
+ private static class NoopSource implements ClassSource {
+ @Override
+ public void eachClass(BiConsumer<String, ClassLoader> consumer) {
+ }
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java
new file mode 100644
index 000000000..a2cf4f542
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @requires vm.aot
+ * @modules jdk.aot/jdk.tools.jaotc
+ * jdk.aot/jdk.tools.jaotc.collect
+ * @build jdk.tools.jaotc.test.collect.Utils
+ * @run junit/othervm jdk.tools.jaotc.test.collect.ClassSourceTest
+ */
+
+package jdk.tools.jaotc.test.collect;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.nio.file.Paths;
+
+import static jdk.tools.jaotc.collect.ClassSource.makeClassName;
+
+import static jdk.tools.jaotc.test.collect.Utils.getpath;
+
+public class ClassSourceTest {
+ @Test(expected=IllegalArgumentException.class)
+ public void itShouldThrowExceptionIfPathDoesntEndWithClass() {
+ makeClassName(Paths.get("Bar.clazz"));
+ }
+
+ @Test
+ public void itShouldReplaceSlashesWithDots() {
+ Assert.assertEquals("foo.Bar", makeClassName(getpath("foo/Bar.class")));
+ }
+
+ @Test
+ public void itShouldStripLeadingSlash() {
+ Assert.assertEquals("Hello", makeClassName(getpath("/Hello.class")));
+ }
+
+ @Test
+ public void itShouldReplaceMultipleDots() {
+ Assert.assertEquals("some.foo.bar.FooBar", makeClassName(getpath("/some/foo/bar/FooBar.class")));
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java
new file mode 100644
index 000000000..7784d0b46
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.test.collect;
+
+import java.net.MalformedURLException;
+import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.Set;
+
+import jdk.tools.jaotc.collect.FileSupport;
+
+public class FakeFileSupport extends FileSupport {
+ private final Set<String> exists = new HashSet<>();
+ private final Set<String> directories = new HashSet<>();
+
+ private final Set<String> checkedExists = new HashSet<>();
+ private final Set<String> checkedDirectory = new HashSet<>();
+ private final Set<String> checkedJarFileSystemRoots = new HashSet<>();
+ private final Set<String> classloaderPaths = new HashSet<>();
+
+ private Path jarFileSystemRoot = null;
+ private final ClassLoader classLoader;
+
+ public FakeFileSupport(Set<String> existing, Set<String> directories) {
+ this.exists.addAll(existing);
+ this.directories.addAll(directories);
+
+ classLoader = new ClassLoader() {
+ @Override
+ public Class<?> loadClass(String name) throws ClassNotFoundException {
+ return null;
+ }
+ };
+ }
+
+ public void setJarFileSystemRoot(Path path) {
+ jarFileSystemRoot = path;
+ }
+
+ @Override
+ public boolean exists(Path path) {
+ checkedExists.add(path.toString());
+ return exists.contains(path.toString());
+ }
+
+ @Override
+ public boolean isDirectory(Path path) {
+ checkedDirectory.add(path.toString());
+ return directories.contains(path.toString());
+ }
+
+ @Override
+ public ClassLoader createClassLoader(Path path) throws MalformedURLException {
+ classloaderPaths.add(path.toString());
+ return classLoader;
+ }
+
+ @Override
+ public Path getJarFileSystemRoot(Path jarFile) {
+ checkedJarFileSystemRoots.add(jarFile.toString());
+ return jarFileSystemRoot;
+ }
+
+ @Override
+ public boolean isAbsolute(Path entry) {
+ return entry.toString().startsWith("/");
+ }
+
+ public void addExist(String name) {
+ exists.add(name);
+ }
+
+ public void addDirectory(String name) {
+ directories.add(name);
+ }
+
+ public Set<String> getCheckedExists() {
+ return checkedExists;
+ }
+
+ public Set<String> getCheckedDirectory() {
+ return checkedDirectory;
+ }
+
+ public Set<String> getCheckedJarFileSystemRoots() {
+ return checkedJarFileSystemRoots;
+ }
+
+ public Set<String> getClassloaderPaths() {
+ return classloaderPaths;
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java
new file mode 100644
index 000000000..93d50bc90
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.test.collect;
+
+import jdk.tools.jaotc.collect.SearchPath;
+
+import java.nio.file.FileSystem;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Set;
+
+import static jdk.tools.jaotc.test.collect.Utils.set;
+
+public class FakeSearchPath extends SearchPath {
+ private Path path = null;
+ public Set<String> entries = set();
+
+ public FakeSearchPath(String name) {
+ if (name != null) {
+ path = Paths.get(name);
+ }
+ }
+
+ @Override
+ public Path find(FileSystem fileSystem, Path entry, String... defaults) {
+ entries.add(entry.toString());
+ return path;
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java
new file mode 100644
index 000000000..172b731ce
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @requires vm.aot
+ * @modules jdk.aot/jdk.tools.jaotc
+ * jdk.aot/jdk.tools.jaotc.collect
+ *
+ * @build jdk.tools.jaotc.test.collect.Utils
+ * @build jdk.tools.jaotc.test.collect.FakeFileSupport
+ * @run junit/othervm jdk.tools.jaotc.test.collect.SearchPathTest
+ */
+
+package jdk.tools.jaotc.test.collect;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.tools.jaotc.collect.*;
+
+import static jdk.tools.jaotc.test.collect.Utils.set;
+import static jdk.tools.jaotc.test.collect.Utils.mkpath;
+import static jdk.tools.jaotc.test.collect.Utils.mkpaths;
+import static org.junit.Assert.*;
+
+public class SearchPathTest {
+ private FakeFileSupport fileSupport;
+ private FileSystem fs;
+
+ @Before
+ public void setUp() throws Exception {
+ fs = FileSystems.getDefault();
+ }
+
+ @Test
+ public void itShouldUsePathIfPathIsAbsoluteAndExisting() {
+ fileSupport = new FakeFileSupport(mkpaths("/foo"), set());
+ SearchPath target = new SearchPath(fileSupport);
+ Path foo = Paths.get(mkpath("/foo"));
+ Path result = target.find(fs, foo);
+ assertSame(result, foo);
+ }
+
+ @Test
+ public void itShouldReturnNullIfPathIsAbsoluteAndNonExisting() {
+ fileSupport = new FakeFileSupport(set(), set());
+ SearchPath target = new SearchPath(fileSupport);
+ Path result = target.find(fs, Paths.get(mkpath("/bar")));
+ assertNull(result);
+ }
+
+ @Test
+ public void itShouldUseRelativeExisting() {
+ fileSupport = new FakeFileSupport(mkpaths("hello", "tmp/hello", "search/hello"), set());
+ SearchPath target = new SearchPath(fileSupport);
+ target.add("search");
+ Path hello = Paths.get("hello");
+ Path result = target.find(fs, hello, "tmp");
+ assertSame(result, hello);
+ }
+
+ @Test
+ public void itShouldSearchDefaultsBeforeSearchPaths() {
+ fileSupport = new FakeFileSupport(mkpaths("bar/foobar"), set());
+ SearchPath target = new SearchPath(fileSupport);
+ Path result = target.find(fs, Paths.get("foobar"), "default1", "bar");
+ assertEquals(mkpath("bar/foobar"), result.toString());
+ assertEquals(mkpaths("foobar", "default1/foobar", "bar/foobar"), fileSupport.getCheckedExists());
+ }
+
+ @Test
+ public void itShouldUseSearchPathsIfNotInDefaults() {
+ fileSupport = new FakeFileSupport(mkpaths("bar/tmp/foobar"), set());
+ SearchPath target = new SearchPath(fileSupport);
+ target.add("foo/tmp", "bar/tmp");
+
+ Path result = target.find(fs, Paths.get("foobar"), "foo", "bar");
+ assertEquals(mkpath("bar/tmp/foobar"), result.toString());
+ assertEquals(mkpaths("foobar", "foo/foobar", "bar/foobar", "bar/tmp/foobar", "foo/tmp/foobar"), fileSupport.getCheckedExists());
+ }
+
+ @Test
+ public void itShouldReturnNullIfNoExistingPathIsFound() {
+ fileSupport = new FakeFileSupport(set(), set());
+ SearchPath target = new SearchPath(fileSupport);
+ target.add("dir1", "dir2");
+
+ Path result = target.find(fs, Paths.get("entry"), "dir3", "dir4");
+ assertNull(result);
+ assertEquals(mkpaths("entry", "dir1/entry", "dir2/entry", "dir3/entry", "dir4/entry"), fileSupport.getCheckedExists());
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/Utils.java b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/Utils.java
new file mode 100644
index 000000000..1ac63782e
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/Utils.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.test.collect;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashSet;
+import java.util.Set;
+
+public class Utils {
+ public static <T> Set<T> set(T... entries) {
+ Set<T> set = new HashSet<T>();
+ for (T entry : entries) {
+ set.add(entry);
+ }
+ return set;
+ }
+
+ public static String mkpath(String path) {
+ return getpath(path).toString();
+ }
+
+ public static Set<String> mkpaths(String... paths) {
+ Set<String> set = new HashSet<String>();
+ for (String entry : paths) {
+ set.add(mkpath(entry));
+ }
+ return set;
+ }
+
+ public static Path getpath(String path) {
+ if (path.startsWith("/") && System.getProperty("os.name").startsWith("Windows")) {
+ path = new File(path).getAbsolutePath();
+ }
+ return Paths.get(path);
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java
new file mode 100644
index 000000000..ed148be5e
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @requires vm.aot
+ * @modules jdk.aot/jdk.tools.jaotc
+ * jdk.aot/jdk.tools.jaotc.collect
+ * jdk.aot/jdk.tools.jaotc.collect.directory
+ * @compile ../Utils.java
+ * @compile ../FakeFileSupport.java
+ * @run junit/othervm jdk.tools.jaotc.test.collect.directory.DirectorySourceProviderTest
+ */
+
+package jdk.tools.jaotc.test.collect.directory;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.directory.DirectorySourceProvider;
+import jdk.tools.jaotc.test.collect.FakeFileSupport;
+import jdk.tools.jaotc.collect.FileSupport;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.net.MalformedURLException;
+import java.nio.file.Path;
+import java.util.Set;
+
+import static jdk.tools.jaotc.test.collect.Utils.set;
+
+public class DirectorySourceProviderTest {
+ @Test
+ public void itShouldReturnNullForNonExistantPath() {
+ DirectorySourceProvider target = new DirectorySourceProvider(new FakeFileSupport(set(), set()));
+ ClassSource result = target.findSource("hello", null);
+ Assert.assertNull(result);
+ }
+
+ @Test
+ public void itShouldReturnNullForNonDirectory() {
+ DirectorySourceProvider target = new DirectorySourceProvider(new FakeFileSupport(set("foobar"), set()));
+ ClassSource result = target.findSource("foobar", null);
+ Assert.assertNull(result);
+ }
+
+ @Test
+ public void itShouldReturnNullForMalformedURI() {
+ Set<String> visited = set();
+ DirectorySourceProvider target = new DirectorySourceProvider(new FakeFileSupport(set("foobar"), set("foobar")) {
+ @Override
+ public ClassLoader createClassLoader(Path path) throws MalformedURLException {
+ visited.add("1");
+ throw new MalformedURLException("...");
+ }
+ });
+ ClassSource result = target.findSource("foobar", null);
+ Assert.assertNull(result);
+ Assert.assertEquals(set("1"), visited);
+ }
+
+ @Test
+ public void itShouldCreateSourceIfNameExistsAndIsADirectory() {
+ FileSupport fileSupport = new FakeFileSupport(set("foo"), set("foo"));
+ DirectorySourceProvider target = new DirectorySourceProvider(fileSupport);
+ ClassSource foo = target.findSource("foo", null);
+ Assert.assertNotNull(foo);
+ Assert.assertEquals("directory:foo", foo.toString());
+ }
+
+}
diff --git a/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java
new file mode 100644
index 000000000..a1eb78d04
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @requires vm.aot
+ * @modules jdk.aot/jdk.tools.jaotc
+ * jdk.aot/jdk.tools.jaotc.collect
+ * jdk.aot/jdk.tools.jaotc.collect.jar
+ * @compile ../Utils.java
+ * @compile ../FakeFileSupport.java
+ * @compile ../FakeSearchPath.java
+ *
+ * @run junit/othervm jdk.tools.jaotc.test.collect.jar.JarSourceProviderTest
+ */
+
+package jdk.tools.jaotc.test.collect.jar;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.jar.JarSourceProvider;
+import jdk.tools.jaotc.test.collect.FakeFileSupport;
+import jdk.tools.jaotc.test.collect.FakeSearchPath;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.ProviderNotFoundException;
+import java.util.Set;
+
+import static jdk.tools.jaotc.test.collect.Utils.mkpath;
+import static jdk.tools.jaotc.test.collect.Utils.set;
+
+public class JarSourceProviderTest {
+
+ private FakeFileSupport fileSupport;
+ private JarSourceProvider target;
+
+ @Before
+ public void setUp() throws Exception {
+ fileSupport = new FakeFileSupport(set(), set());
+ target = new JarSourceProvider(fileSupport);
+ }
+
+ @Test
+ public void itShouldUseSearchPathToFindPath() {
+ Set<String> visited = set();
+ JarSourceProvider target = new JarSourceProvider(fileSupport);
+ FakeSearchPath searchPath = new FakeSearchPath(null);
+ ClassSource source = target.findSource("hello", searchPath);
+
+ Assert.assertEquals(set("hello"), searchPath.entries);
+ }
+
+ @Test
+ public void itShouldReturnNullIfPathIsNull() {
+ JarSourceProvider target = new JarSourceProvider(fileSupport);
+ ClassSource source = target.findSource("foobar", new FakeSearchPath(null));
+ Assert.assertNull(source);
+ }
+
+ @Test
+ public void itShouldReturnNullIfPathIsDirectory() {
+ fileSupport.addDirectory("hello/foobar");
+ ClassSource source = target.findSource("foobar", new FakeSearchPath("hello/foobar"));
+
+ Assert.assertNull(source);
+ Assert.assertEquals(set(mkpath("hello/foobar")), fileSupport.getCheckedDirectory());
+ }
+
+ @Test
+ public void itShouldReturnNullIfUnableToMakeJarFileSystem() {
+ fileSupport.setJarFileSystemRoot(null);
+ ClassSource result = target.findSource("foobar", new FakeSearchPath("foo/bar"));
+
+ Assert.assertEquals(set(mkpath("foo/bar")), fileSupport.getCheckedJarFileSystemRoots());
+ Assert.assertNull(result);
+ }
+
+ @Test
+ public void itShouldReturnNullIfNotValidJarProvider() {
+ fileSupport = new FakeFileSupport(set(), set()) {
+
+ @Override
+ public Path getJarFileSystemRoot(Path jarFile) {
+ super.getJarFileSystemRoot(jarFile);
+ throw new ProviderNotFoundException();
+ }
+ };
+ fileSupport.setJarFileSystemRoot(null);
+ target = new JarSourceProvider(fileSupport);
+
+ ClassSource result = target.findSource("foobar", new FakeSearchPath("foo/bar"));
+
+ Assert.assertEquals(set(mkpath("foo/bar")), fileSupport.getCheckedJarFileSystemRoots());
+ Assert.assertNull(result);
+ }
+
+ @Test
+ public void itShouldReturnSourceWhenAllIsValid() {
+ fileSupport.setJarFileSystemRoot(Paths.get("some/bar"));
+ ClassSource result = target.findSource("foobar", new FakeSearchPath("this/bar"));
+
+ Assert.assertEquals(set(mkpath("this/bar")), fileSupport.getClassloaderPaths());
+ Assert.assertEquals("jar:" + mkpath("this/bar"), result.toString());
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java
new file mode 100644
index 000000000..4bf2b9ca1
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @requires vm.aot
+ * @modules jdk.aot/jdk.tools.jaotc
+ * jdk.aot/jdk.tools.jaotc.collect
+ * jdk.aot/jdk.tools.jaotc.collect.module
+ * @compile ../Utils.java
+ * @run junit/othervm jdk.tools.jaotc.test.collect.module.ModuleSourceProviderTest
+ */
+
+package jdk.tools.jaotc.test.collect.module;
+
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.module.ModuleSource;
+import jdk.tools.jaotc.collect.module.ModuleSourceProvider;
+import jdk.tools.jaotc.test.collect.Utils;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.function.BiFunction;
+
+import static jdk.tools.jaotc.test.collect.Utils.mkpath;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+
+public class ModuleSourceProviderTest {
+ private ClassLoader classLoader;
+ private ModuleSourceProvider target;
+ private FileSupport fileSupport;
+ private BiFunction<Path, Path, Path> getSubDirectory = null;
+
+ @Before
+ public void setUp() {
+ classLoader = new FakeClassLoader();
+ fileSupport = new FileSupport() {
+
+ @Override
+ public boolean isDirectory(Path path) {
+ return true;
+ }
+
+ @Override
+ public Path getSubDirectory(FileSystem fileSystem, Path root, Path path) throws IOException {
+ if (getSubDirectory == null) {
+ throw new IOException("Nope");
+ }
+ return getSubDirectory.apply(root, path);
+ }
+ };
+ target = new ModuleSourceProvider(FileSystems.getDefault(), classLoader, fileSupport);
+ }
+
+ @Test
+ public void itShouldUseFileSupport() {
+ getSubDirectory = (root, path) -> {
+ if (root.toString().equals("modules") && path.toString().equals("test.module")) {
+ return Paths.get("modules/test.module");
+ }
+ return null;
+ };
+
+ ModuleSource source = (ModuleSource) target.findSource("test.module", null);
+ assertEquals(mkpath("modules/test.module"), source.getModulePath().toString());
+ assertEquals("module:" + mkpath("modules/test.module"), source.toString());
+ }
+
+ private static class FakeClassLoader extends ClassLoader {
+ @Override
+ public Class<?> loadClass(String name) throws ClassNotFoundException {
+ return null;
+ }
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/scripts/HelloWorld.java b/test/hotspot/jtreg/compiler/aot/scripts/HelloWorld.java
new file mode 100644
index 000000000..663161b63
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/scripts/HelloWorld.java
@@ -0,0 +1,5 @@
+public class HelloWorld {
+ public static void main(String[] args) {
+ System.out.println("Hello, world!");
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/scripts/InitGraal.java b/test/hotspot/jtreg/compiler/aot/scripts/InitGraal.java
new file mode 100644
index 000000000..ed1bffd8a
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/scripts/InitGraal.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import jdk.vm.ci.hotspot.*;
+
+public class InitGraal {
+ public static void main(String[] args) throws Throwable {
+ HotSpotJVMCIRuntime.runtime().getCompiler();
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/scripts/README b/test/hotspot/jtreg/compiler/aot/scripts/README
new file mode 100644
index 000000000..c1fb204d6
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/scripts/README
@@ -0,0 +1,32 @@
+Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+This code is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 2 only, as
+published by the Free Software Foundation.
+
+This code is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+version 2 for more details (a copy is included in the LICENSE file that
+accompanied this code).
+
+You should have received a copy of the GNU General Public License version
+2 along with this work; if not, write to the Free Software Foundation,
+Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+or visit www.oracle.com if you need additional information or have any
+questions.
+
+--------------------------------------------
+This directory contains scripts to test AOT.
+
+JAVA_HOME should point to local JDK (scripts will install AOT libraries into it) which supports AOT.
+
+Use 'bash' shell to run scripts.
+
+Execute build-bootmodules.sh first before running test* scripts.
+
+Download dacapo-9.12-bach.jar and execute build-jdk.vm-modules.sh before running test-graal.sh
+
diff --git a/test/hotspot/jtreg/compiler/aot/scripts/build-bootmodules.sh b/test/hotspot/jtreg/compiler/aot/scripts/build-bootmodules.sh
new file mode 100644
index 000000000..5400700ee
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/scripts/build-bootmodules.sh
@@ -0,0 +1,106 @@
+# Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+pushd `dirname $0` > /dev/null
+DIR=`pwd`
+popd > /dev/null
+
+# set env variables
+. $DIR/test-env.sh
+
+MODULES="java.base"
+
+TEST=HelloWorld
+
+for m in $MODULES; do
+ rm -f $JAVA_HOME/lib/lib$m*.$SO_TYPE
+done
+
+$JAVA_HOME/bin/javac -d . $DIR/$TEST.java
+
+JAOTC_OPTS="-J-ea -J-Xmx4g --compile-for-tiered --info"
+JAVA_OPTS="-Xmx4g -XX:+UnlockExperimentalVMOptions -XX:+UseAOT -XX:+UnlockDiagnosticVMOptions -XX:+UseAOTStrictLoading"
+
+# Compile with: +UseCompressedOops +UseG1GC
+LIBRARIES=""
+for m in $MODULES; do
+ if [ -f $DIR/$m-list.txt ]; then
+ LIST="--compile-commands $DIR/$m-list.txt"
+ else
+ LIST=""
+ fi
+ $JAVA_HOME/bin/jaotc -J-XX:+UseCompressedOops -J-XX:+UseG1GC $JAOTC_OPTS $LIST --output lib$m-coop.$SO_TYPE --module $m || exit 1
+ LIBRARIES="$LIBRARIES$PWD/lib$m-coop.$SO_TYPE:"
+done
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:+UseCompressedOops -XX:+UseG1GC -XX:AOTLibrary=$LIBRARIES $TEST || exit 1
+
+# Compile with: +UseCompressedOops +UseParallelGC
+LIBRARIES=""
+for m in $MODULES; do
+ if [ -f $DIR/$m-list.txt ]; then
+ LIST="--compile-commands $DIR/$m-list.txt"
+ else
+ LIST=""
+ fi
+ $JAVA_HOME/bin/jaotc -J-XX:+UseCompressedOops -J-XX:+UseParallelGC $JAOTC_OPTS $LIST --output lib$m-coop-nong1.$SO_TYPE --module $m || exit 1
+ LIBRARIES="$LIBRARIES$PWD/lib$m-coop-nong1.$SO_TYPE:"
+done
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:+UseCompressedOops -XX:+UseParallelGC -XX:AOTLibrary=$LIBRARIES $TEST || exit 1
+
+# Compile with: -UseCompressedOops +UseG1GC
+LIBRARIES=""
+for m in $MODULES; do
+ if [ -f $DIR/$m-list.txt ]; then
+ LIST="--compile-commands $DIR/$m-list.txt"
+ else
+ LIST=""
+ fi
+ $JAVA_HOME/bin/jaotc -J-XX:-UseCompressedOops -J-XX:+UseG1GC $JAOTC_OPTS $LIST --output lib$m.$SO_TYPE --module $m || exit 1
+ LIBRARIES="$LIBRARIES$PWD/lib$m.$SO_TYPE:"
+done
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:-UseCompressedOops -XX:+UseG1GC -XX:AOTLibrary=$LIBRARIES $TEST || exit 1
+
+# Compile with: -UseCompressedOops +UseParallelGC
+LIBRARIES=""
+for m in $MODULES; do
+ if [ -f $DIR/$m-list.txt ]; then
+ LIST="--compile-commands $DIR/$m-list.txt"
+ else
+ LIST=""
+ fi
+ $JAVA_HOME/bin/jaotc -J-XX:-UseCompressedOops -J-XX:+UseParallelGC $JAOTC_OPTS $LIST --output lib$m-nong1.$SO_TYPE --module $m || exit 1
+ LIBRARIES="$LIBRARIES$PWD/lib$m-nong1.$SO_TYPE:"
+done
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:-UseCompressedOops -XX:+UseParallelGC -XX:AOTLibrary=$LIBRARIES $TEST || exit 1
+
+echo "Installing shared libraries in: $JAVA_HOME/lib/"
+for m in $MODULES; do
+ mv -f lib$m*.$SO_TYPE $JAVA_HOME/lib/
+done
+
+# Test installed libraries.
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:-UseCompressedOops -XX:+UseG1GC -XX:+PrintAOT $TEST | grep "aot library" || exit 1
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:-UseCompressedOops -XX:+UseParallelGC -XX:+PrintAOT $TEST | grep "aot library" || exit 1
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:+UseCompressedOops -XX:+UseG1GC -XX:+PrintAOT $TEST | grep "aot library" || exit 1
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:+UseCompressedOops -XX:+UseParallelGC -XX:+PrintAOT $TEST | grep "aot library" || exit 1
+
+rm -f $TEST.class
+
diff --git a/test/hotspot/jtreg/compiler/aot/scripts/build-jdk.vm-modules.sh b/test/hotspot/jtreg/compiler/aot/scripts/build-jdk.vm-modules.sh
new file mode 100644
index 000000000..473d4717a
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/scripts/build-jdk.vm-modules.sh
@@ -0,0 +1,110 @@
+# Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+pushd `dirname $0` > /dev/null
+DIR=`pwd`
+popd > /dev/null
+
+# set env variables
+. $DIR/test-env.sh
+
+MODULES="jdk.internal.vm.ci jdk.internal.vm.compiler"
+
+TEST=InitGraal
+
+for m in $MODULES; do
+ rm -f $JAVA_HOME/lib/lib$m*.$SO_TYPE
+done
+
+$JAVA_HOME/bin/javac --add-modules jdk.internal.vm.ci --add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot=ALL-UNNAMED $DIR/$TEST.java
+
+# AOT compile non-tiered code version.
+JAOTC_OPTS="-J-Xmx4g --info"
+JAVA_OPTS="-Xmx4g -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:+UseAOT -XX:+UnlockDiagnosticVMOptions -XX:+UseAOTStrictLoading --add-modules jdk.internal.vm.ci --add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot=ALL-UNNAMED"
+
+# Compile with: +UseCompressedOops +UseG1GC
+RT_OPTS="-J-XX:+UseCompressedOops -J-XX:+UseG1GC"
+LIBRARIES=""
+for m in $MODULES; do
+ if [ -f $DIR/$m-list.txt ]; then
+ LIST="--compile-commands $DIR/$m-list.txt"
+ else
+ LIST=""
+ fi
+ $JAVA_HOME/bin/jaotc $RT_OPTS $JAOTC_OPTS $LIST --output lib$m-coop.$SO_TYPE --module $m -J-XX:AOTLibrary=$LIBRARIES || exit 1
+ LIBRARIES="$LIBRARIES$PWD/lib$m-coop.$SO_TYPE:"
+done
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:+UseCompressedOops -XX:+UseG1GC -XX:+PrintAOT -XX:AOTLibrary=$LIBRARIES $TEST | grep "aot library" || exit 1
+
+# Compile with: +UseCompressedOops +UseParallelGC
+RT_OPTS="-J-XX:+UseCompressedOops -J-XX:+UseParallelGC"
+LIBRARIES=""
+for m in $MODULES; do
+ if [ -f $DIR/$m-list.txt ]; then
+ LIST="--compile-commands $DIR/$m-list.txt"
+ else
+ LIST=""
+ fi
+ $JAVA_HOME/bin/jaotc $RT_OPTS $JAOTC_OPTS $LIST --output lib$m-coop-nong1.$SO_TYPE --module $m -J-XX:AOTLibrary=$LIBRARIES || exit 1
+ LIBRARIES="$LIBRARIES$PWD/lib$m-coop-nong1.$SO_TYPE:"
+done
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:+UseCompressedOops -XX:+UseParallelGC -XX:+PrintAOT -XX:AOTLibrary=$LIBRARIES $TEST | grep "aot library" || exit 1
+
+# Compile with: -UseCompressedOops +UseG1GC
+RT_OPTS="-J-XX:-UseCompressedOops -J-XX:+UseG1GC"
+LIBRARIES=""
+for m in $MODULES; do
+ if [ -f $DIR/$m-list.txt ]; then
+ LIST="--compile-commands $DIR/$m-list.txt"
+ else
+ LIST=""
+ fi
+ $JAVA_HOME/bin/jaotc $RT_OPTS $JAOTC_OPTS $LIST --output lib$m.$SO_TYPE --module $m -J-XX:AOTLibrary=$LIBRARIES || exit 1
+ LIBRARIES="$LIBRARIES$PWD/lib$m.$SO_TYPE:"
+done
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:-UseCompressedOops -XX:+UseG1GC -XX:+PrintAOT -XX:AOTLibrary=$LIBRARIES $TEST | grep "aot library" || exit 1
+
+# Compile with: -UseCompressedOops +UseParallelGC
+RT_OPTS="-J-XX:-UseCompressedOops -J-XX:+UseParallelGC"
+LIBRARIES=""
+for m in $MODULES; do
+ if [ -f $DIR/$m-list.txt ]; then
+ LIST="--compile-commands $DIR/$m-list.txt"
+ else
+ LIST=""
+ fi
+ $JAVA_HOME/bin/jaotc $RT_OPTS $JAOTC_OPTS $LIST --output lib$m-nong1.$SO_TYPE --module $m -J-XX:AOTLibrary=$LIBRARIES || exit 1
+ LIBRARIES="$LIBRARIES$PWD/lib$m-nong1.$SO_TYPE:"
+done
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:-UseCompressedOops -XX:+UseParallelGC -XX:+PrintAOT -XX:AOTLibrary=$LIBRARIES $TEST | grep "aot library" || exit 1
+
+echo "Installing shared libraries in: $JAVA_HOME/lib/"
+for m in $MODULES; do
+ mv -f lib$m*.$SO_TYPE $JAVA_HOME/lib/
+done
+
+# Test installed libraries.
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:-UseCompressedOops -XX:+UseG1GC -XX:+PrintAOT $TEST | grep "aot library" || exit 1
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:-UseCompressedOops -XX:+UseParallelGC -XX:+PrintAOT $TEST | grep "aot library" || exit 1
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:+UseCompressedOops -XX:+UseG1GC -XX:+PrintAOT $TEST | grep "aot library" || exit 1
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:+UseCompressedOops -XX:+UseParallelGC -XX:+PrintAOT $TEST | grep "aot library" || exit 1
+
+rm -f $TEST.class
diff --git a/test/hotspot/jtreg/compiler/aot/scripts/empty.js b/test/hotspot/jtreg/compiler/aot/scripts/empty.js
new file mode 100644
index 000000000..226697f87
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/scripts/empty.js
@@ -0,0 +1 @@
+i = 0;
diff --git a/test/hotspot/jtreg/compiler/aot/scripts/java.base-list.txt b/test/hotspot/jtreg/compiler/aot/scripts/java.base-list.txt
new file mode 100644
index 000000000..380a4586c
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/scripts/java.base-list.txt
@@ -0,0 +1,20 @@
+# Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
diff --git a/test/hotspot/jtreg/compiler/aot/scripts/jdk.internal.vm.compiler-list.txt b/test/hotspot/jtreg/compiler/aot/scripts/jdk.internal.vm.compiler-list.txt
new file mode 100644
index 000000000..59b4eba7d
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/scripts/jdk.internal.vm.compiler-list.txt
@@ -0,0 +1,45 @@
+# Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+#
+exclude org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyCallNode.*
+exclude org.graalvm.compiler.hotspot.replacements.AESCryptSubstitutions.*
+exclude org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions.crypt(Ljava/lang/Object;[BII[BILjava/lang/Object;ZZ)V
+exclude org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayAllocationSize(III)I
+exclude org.graalvm.compiler.hotspot.replacements.PluginFactory_HotSpotReplacementsUtil\$config.execute(.*).*
+exclude org.graalvm.compiler.hotspot.replacements.PluginFactory_HotSpotReplacementsUtil\$getWordKind.execute(.*).*
+exclude org.graalvm.compiler.hotspot.replacements.PluginFactory_HotSpotReplacementsUtil\$getConfig.execute(.*).
+#
+exclude org.graalvm.compiler.hotspot.stubs.StubUtil.printf(.*).*
+exclude org.graalvm.compiler.hotspot.stubs.StubUtil.decipher(J)V
+exclude org.graalvm.compiler.hotspot.stubs.StubUtil.fatal(.*).*
+#
+exclude org.graalvm.compiler.nodes.java.NewArrayNode.newUninitializedArray(Ljava/lang/Class;I)Ljava/lang/Object;
+exclude org.graalvm.compiler.nodes.java.DynamicNewArrayNode.newArray(Ljava/lang/Class;ILjdk/vm/ci/meta/JavaKind;)Ljava/lang/Object;
+exclude org.graalvm.compiler.nodes.java.DynamicNewArrayNode.newUninitializedArray(Ljava/lang/Class;ILjdk/vm/ci/meta/JavaKind;)Ljava/lang/Object;
+exclude org.graalvm.compiler.nodes.PiNode.piCastNonNull(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
+#
+exclude org.graalvm.compiler.replacements.nodes.ArrayEqualsNode.equals(.*).*
+exclude org.graalvm.compiler.replacements.Log.print.*
+exclude org.graalvm.compiler.replacements.ReplacementsUtil.*
+exclude org.graalvm.compiler.replacements.SnippetCounter.*
+exclude org.graalvm.compiler.replacements.SnippetCounterNode.*
+exclude org.graalvm.compiler.replacements.SnippetIntegerHistogram.inc(J)V
diff --git a/test/hotspot/jtreg/compiler/aot/scripts/test-env.sh b/test/hotspot/jtreg/compiler/aot/scripts/test-env.sh
new file mode 100644
index 000000000..ac660724b
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/scripts/test-env.sh
@@ -0,0 +1,42 @@
+# Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+# set platform-dependent variables
+OS=`uname -s`
+case "$OS" in
+ Linux )
+ SO_TYPE=so
+ ;;
+ Darwin )
+ SO_TYPE=dylib
+ ;;
+ Windows_* )
+ SO_TYPE=dll
+ ;;
+ CYGWIN_* )
+ SO_TYPE=dll
+ ;;
+ * )
+ echo "Unrecognized system!"
+ exit 1;
+ ;;
+esac
+
diff --git a/test/hotspot/jtreg/compiler/aot/scripts/test-graal.sh b/test/hotspot/jtreg/compiler/aot/scripts/test-graal.sh
new file mode 100644
index 000000000..d2f77d22c
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/scripts/test-graal.sh
@@ -0,0 +1,62 @@
+# Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+JAR="dacapo-9.12-bach.jar"
+
+if [ ! -f $JAR ]; then
+ echo "$JAR not found."
+ exit 1
+fi
+
+pushd `dirname $0` > /dev/null
+DIR=`pwd`
+popd > /dev/null
+
+APP="-jar $JAR -s small -n 5"
+
+JAVA_OPTS="-XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:+UseJVMCICompiler -XX:-BootstrapJVMCI -XX:-TieredCompilation -Xmx4g -XX:+UseCompressedOops -XX:+UseG1GC"
+
+MODULE_OPTS="--add-modules jdk.internal.vm.ci --add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot=ALL-UNNAMED"
+
+$JAVA_HOME/bin/java $JAVA_OPTS -version || exit 1
+
+$JAVA_HOME/bin/javac $MODULE_OPTS InitGraal.java || exit 1
+
+PATTERN="(aot library|DONE:.*HotSpotVMConfig|DONE:.*HotSpotJVMCIRuntime|DONE:.*HotSpotGraalRuntime)"
+echo "----------"
+$JAVA_HOME/bin/java $JAVA_OPTS $MODULE_OPTS -XX:+TieredCompilation -XX:-UseAOT -XX:+PrintAOT -Djvmci.InitTimer=true InitGraal | grep -E "$PATTERN" || exit 1
+echo "----------"
+$JAVA_HOME/bin/java $JAVA_OPTS $MODULE_OPTS -XX:+TieredCompilation -XX:+PrintAOT -Djvmci.InitTimer=true InitGraal | grep -E "$PATTERN" || exit 1
+echo "----------"
+$JAVA_HOME/bin/java $JAVA_OPTS $MODULE_OPTS -XX:+PrintAOT -Djvmci.InitTimer=true InitGraal | grep -E "$PATTERN" || exit 1
+echo "----------"
+
+rm -f InitGraal.class
+
+# eclipse started to fail again with JDK 9.
+#BENCHMARKS="avrora batik eclipse fop jython h2 luindex lusearch pmd sunflow tradebeans tradesoap xalan"
+BENCHMARKS="avrora batik fop jython h2 luindex lusearch pmd sunflow xalan"
+
+for i in $BENCHMARKS; do
+ $JAVA_HOME/bin/java $JAVA_OPTS $APP $i || exit 1
+ rm -rf ./scratch
+done
+
diff --git a/test/hotspot/jtreg/compiler/aot/scripts/test-helloworld.sh b/test/hotspot/jtreg/compiler/aot/scripts/test-helloworld.sh
new file mode 100644
index 000000000..860b0ee21
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/scripts/test-helloworld.sh
@@ -0,0 +1,97 @@
+# Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+pushd `dirname $0` > /dev/null
+DIR=`pwd`
+popd > /dev/null
+
+# set env variables
+. $DIR/test-env.sh
+
+rm -f libHelloWorld*.$SO_TYPE HelloWorld.class
+
+$JAVA_HOME/bin/javac -d . $DIR/HelloWorld.java
+
+# Run once with non-compressed oops.
+OPTS="-J-Xmx4g -J-XX:-UseCompressedOops --info --verbose"
+$JAVA_HOME/bin/jaotc $OPTS --output libHelloWorld.$SO_TYPE HelloWorld.class || exit 1
+
+JAVA_OPTS="-Xmx4g -XX:-UseCompressedOops -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseAOTStrictLoading -XX:AOTLibrary=./libHelloWorld.$SO_TYPE"
+
+$JAVA_HOME/bin/java $JAVA_OPTS -XX:+PrintAOT -version | grep "aot library" || exit 1
+$JAVA_HOME/bin/java $JAVA_OPTS HelloWorld || exit 1
+
+TIMEFORMAT="%3R"
+N=5
+
+LIBRARY=libHelloWorld-coop.$SO_TYPE
+
+for gc in UseG1GC UseParallelGC; do
+ # Now with compressed oops.
+ OPTS="-J-XX:+UseCompressedOops -J-XX:+$gc --info --verbose"
+ $JAVA_HOME/bin/jaotc $OPTS --output $LIBRARY HelloWorld.class
+
+ # Dump CDS archive.
+ $JAVA_HOME/bin/java -Xshare:dump -XX:+UnlockExperimentalVMOptions -XX:-UseAOT -XX:+$gc || exit 1
+
+ JAVA_OPTS="-Xmx256m"
+
+ echo "Tiered C1 $gc:"
+ for i in `seq 1 $N`; do
+ OUT=`time $JAVA_HOME/bin/java -XX:+$gc -XX:-UseCompressedOops -XX:+UnlockExperimentalVMOptions -XX:-UseAOT -XX:TieredStopAtLevel=1 $JAVA_OPTS HelloWorld`
+ if [ "$OUT" != "Hello, world!" ]; then
+ echo $OUT
+ exit 1
+ fi
+ done
+
+ echo "Tiered C1/C2 $gc:"
+ for i in `seq 1 $N`; do
+ OUT=`time $JAVA_HOME/bin/java -XX:+$gc -XX:-UseCompressedOops -XX:+UnlockExperimentalVMOptions -XX:-UseAOT $JAVA_OPTS HelloWorld`
+ if [ "$OUT" != "Hello, world!" ]; then
+ echo $OUT
+ exit 1
+ fi
+ done
+
+ JAVA_OPTS="-Xmx256m -XX:+UseCompressedOops -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseAOTStrictLoading -XX:AOTLibrary=./$LIBRARY"
+
+
+ echo "AOT $gc:"
+ for i in `seq 1 $N`; do
+ OUT=`time $JAVA_HOME/bin/java -XX:+$gc $JAVA_OPTS HelloWorld`
+ if [ "$OUT" != "Hello, world!" ]; then
+ echo $OUT
+ exit 1
+ fi
+ done
+
+ echo "AOT -Xshare:on $gc:"
+ for i in `seq 1 $N`; do
+ OUT=`time $JAVA_HOME/bin/java -Xshare:on -XX:+$gc $JAVA_OPTS HelloWorld`
+ if [ "$OUT" != "Hello, world!" ]; then
+ echo $OUT
+ exit 1
+ fi
+ done
+done
+
+rm -f libHelloWorld*.$SO_TYPE HelloWorld.class
diff --git a/test/hotspot/jtreg/compiler/aot/scripts/test-jaotc.sh b/test/hotspot/jtreg/compiler/aot/scripts/test-jaotc.sh
new file mode 100644
index 000000000..ca8ec53a1
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/scripts/test-jaotc.sh
@@ -0,0 +1,43 @@
+# Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+pushd `dirname $0` > /dev/null
+DIR=`pwd`
+popd > /dev/null
+
+# set env variables
+. $DIR/test-env.sh
+
+JAOTC_OPTS="-J-Xmx4g -J-XX:-UseCompressedOops"
+
+rm -f libjdk.aot.$SO_TYPE
+
+$JAVA_HOME/bin/jaotc $JAOTC_OPTS --info --module jdk.aot --output libjdk.aot.$SO_TYPE || exit 1
+
+rm -f libjava.base-aot.$SO_TYPE
+
+$JAVA_HOME/bin/jaotc $JAOTC_OPTS -J-XX:AOTLibrary=./libjdk.aot.$SO_TYPE --info --compile-commands $DIR/java.base-list.txt --output libjava.base-aot.$SO_TYPE --module java.base || exit 1
+
+$JAVA_HOME/bin/javac -d . $DIR/HelloWorld.java
+
+$JAVA_HOME/bin/java -XX:-UseCompressedOops -XX:+UnlockExperimentalVMOptions -XX:AOTLibrary=./libjava.base-aot.$SO_TYPE HelloWorld
+
+rm -f HelloWorld.class libjdk.aot.$SO_TYPE libjava.base-aot.$SO_TYPE
diff --git a/test/hotspot/jtreg/compiler/aot/scripts/test-javac.sh b/test/hotspot/jtreg/compiler/aot/scripts/test-javac.sh
new file mode 100644
index 000000000..006c96a63
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/scripts/test-javac.sh
@@ -0,0 +1,157 @@
+# Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+pushd `dirname $0` > /dev/null
+DIR=`pwd`
+popd > /dev/null
+
+AOT_OPTS="-XX:+UnlockExperimentalVMOptions -XX:+UseAOT"
+
+$JAVA_HOME/bin/java $AOT_OPTS -XX:+PrintAOT -version | grep "aot library" || exit 1
+
+# Dump CDS archive.
+$JAVA_HOME/bin/java $AOT_OPTS -Xshare:dump || exit 1
+
+FILE="HelloWorld"
+
+APP="com.sun.tools.javac.Main"
+
+JAVA_OPTS="-XX:-UseCompressedOops"
+
+rm -f $FILE.class
+
+$JAVA_HOME/bin/java $JAVA_OPTS $AOT_OPTS $APP -verbose $FILE.java || exit 1
+$JAVA_HOME/bin/java $AOT_OPTS $FILE || exit 1
+
+JAVA_OPTS="-XX:+UseCompressedOops"
+
+rm -f $FILE.class
+
+$JAVA_HOME/bin/java $JAVA_OPTS $AOT_OPTS $APP -verbose $FILE.java || exit 1
+$JAVA_HOME/bin/java $AOT_OPTS $FILE || exit 1
+
+rm -f $FILE.class
+
+TIMEFORMAT="%3R"
+N=5
+
+#echo "-Xint:"
+#for i in `seq 1 10`; do
+# time $JAVA_HOME/bin/java -Xint $JAVA_OPTS $APP $FILE.java
+# if [ $? -ne 0 ]; then
+# exit 1
+# fi
+# rm -f $FILE.class
+#done
+
+echo "Tiered C1:"
+for i in `seq 1 $N`; do
+ time $JAVA_HOME/bin/java $JAVA_OPTS -XX:+UnlockExperimentalVMOptions -XX:-UseAOT -XX:TieredStopAtLevel=1 $APP $FILE.java
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ rm -f $FILE.class
+done
+
+echo "Tiered C1/C2:"
+for i in `seq 1 $N`; do
+ time $JAVA_HOME/bin/java $JAVA_OPTS -XX:+UnlockExperimentalVMOptions -XX:-UseAOT $APP $FILE.java
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ rm -f $FILE.class
+done
+
+echo "Tiered C1/C2 -Xshare:on:"
+for i in `seq 1 $N`; do
+ time $JAVA_HOME/bin/java $JAVA_OPTS -XX:+UnlockExperimentalVMOptions -XX:-UseAOT -Xshare:on $APP $FILE.java
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ rm -f $FILE.class
+done
+
+echo "Tiered AOT:"
+for i in `seq 1 $N`; do
+ time $JAVA_HOME/bin/java $JAVA_OPTS $AOT_OPTS $APP $FILE.java
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ rm -f $FILE.class
+done
+
+echo "Tiered AOT -Xshare:on:"
+for i in `seq 1 $N`; do
+ time $JAVA_HOME/bin/java $JAVA_OPTS $AOT_OPTS -Xshare:on $APP $FILE.java
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ rm -f $FILE.class
+done
+
+NAME="jvmci"
+DIR="$DIR/../../../../../../src/jdk.internal.vm.ci"
+FILES=`find $DIR -type f -name '*.java'`
+COUNT=`find $DIR -type f -name '*.java' | wc -l`
+
+rm -rf tmp
+
+echo "Tiered C1 (compiling $NAME: $COUNT classes):"
+for i in `seq 1 $N`; do
+ mkdir tmp
+ time $JAVA_HOME/bin/javac -J-XX:+UnlockExperimentalVMOptions -J-XX:-UseAOT -J-XX:TieredStopAtLevel=1 -XDignore.symbol.file -d tmp $FILES
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ rm -rf tmp
+done
+
+echo "Tiered C1/C2 (compiling $NAME: $COUNT classes):"
+for i in `seq 1 $N`; do
+ mkdir tmp
+ time $JAVA_HOME/bin/javac -J-XX:+UnlockExperimentalVMOptions -J-XX:-UseAOT -XDignore.symbol.file -cp /java/devtools/share/junit/latest/junit.jar -d tmp $FILES
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ rm -rf tmp
+done
+
+echo "Tiered AOT (compiling $NAME: $COUNT classes):"
+for i in `seq 1 $N`; do
+ mkdir tmp
+ time $JAVA_HOME/bin/javac -J-XX:+UnlockExperimentalVMOptions -J-XX:+UseAOT -XDignore.symbol.file -cp /java/devtools/share/junit/latest/junit.jar -d tmp $FILES
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ rm -rf tmp
+done
+
+echo "Tiered AOT -Xshare:on (compiling $NAME: $COUNT classes):"
+for i in `seq 1 $N`; do
+ mkdir tmp
+ time $JAVA_HOME/bin/javac -J-Xshare:on -J-XX:+UnlockExperimentalVMOptions -J-XX:+UseAOT -XDignore.symbol.file -cp /java/devtools/share/junit/latest/junit.jar -d tmp $FILES
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ rm -rf tmp
+done
+
+
diff --git a/test/hotspot/jtreg/compiler/aot/verification/ClassAndLibraryNotMatchTest.java b/test/hotspot/jtreg/compiler/aot/verification/ClassAndLibraryNotMatchTest.java
new file mode 100644
index 000000000..ecb2f52fb
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/verification/ClassAndLibraryNotMatchTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.verification.ClassAndLibraryNotMatchTest
+ * @run driver compiler.aot.verification.ClassAndLibraryNotMatchTest
+ * @summary check if class and aot library are properly bound to each other
+ */
+
+package compiler.aot.verification;
+
+import compiler.aot.AotCompiler;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Arrays;
+import jdk.test.lib.JDKToolFinder;
+import jdk.test.lib.Utils;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+public class ClassAndLibraryNotMatchTest {
+ private static final String HELLO_WORLD_CLASS_NAME = "HelloWorld";
+ private static final String LIB_NAME = "lib" + HELLO_WORLD_CLASS_NAME + ".so";
+ private static final String HELLO_WORLD_MSG1 = "HelloWorld1";
+ private static final String HELLO_WORLD_MSG2 = "HelloWorld2";
+ private static final String HELLO_WORLD_FILE = "./" + HELLO_WORLD_CLASS_NAME + ".java";
+ private static final String HELLO_WORLD_PRE = "public class "
+ + HELLO_WORLD_CLASS_NAME + " {\n"
+ + " public static void main(String args[]) {\n"
+ + " System.out.println(\"";
+ private static final String HELLO_WORLD_POST = "\");\n"
+ + " }\n"
+ + "}\n";
+
+ public static void main(String args[]) {
+ new ClassAndLibraryNotMatchTest().runTest();
+ }
+
+ private void writeHelloWorld(String message) {
+ String src = HELLO_WORLD_PRE + message + HELLO_WORLD_POST;
+ try{
+ Files.write(Paths.get(HELLO_WORLD_FILE), src.getBytes(), StandardOpenOption.CREATE);
+ } catch (IOException e) {
+ throw new Error("Can't write HelloWorld " + e, e);
+ }
+ }
+
+ private void compileHelloWorld() {
+ String javac = JDKToolFinder.getCompileJDKTool("javac");
+ ProcessBuilder pb = new ProcessBuilder(javac, HELLO_WORLD_FILE);
+ OutputAnalyzer oa;
+ try {
+ oa = ProcessTools.executeProcess(pb);
+ } catch (Exception e) {
+ throw new Error("Can't compile class " + e, e);
+ }
+ oa.shouldHaveExitValue(0);
+ }
+
+ private void compileAotLibrary() {
+ AotCompiler.launchCompiler(LIB_NAME, HELLO_WORLD_CLASS_NAME,
+ Arrays.asList("-classpath", Utils.TEST_CLASS_PATH + File.pathSeparator + "."), null);
+ }
+
+ private void runAndCheckHelloWorld(String checkString) {
+ ProcessBuilder pb;
+ try {
+ pb = ProcessTools.createTestJvm("-cp", ".",
+ "-XX:+UnlockExperimentalVMOptions", "-XX:+UseAOT",
+ "-XX:AOTLibrary=./" + LIB_NAME, HELLO_WORLD_CLASS_NAME);
+ } catch (Exception e) {
+ throw new Error("Can't create ProcessBuilder to run "
+ + HELLO_WORLD_CLASS_NAME + " " + e, e);
+ }
+ OutputAnalyzer oa;
+ try {
+ oa = ProcessTools.executeProcess(pb);
+ } catch (Exception e) {
+ throw new Error("Can't execute " + HELLO_WORLD_CLASS_NAME + " " + e, e);
+ }
+ oa.shouldHaveExitValue(0);
+ oa.shouldContain(checkString);
+ }
+
+ private void createHelloWorld(String msg) {
+ writeHelloWorld(msg);
+ compileHelloWorld();
+ }
+
+ private void runTest() {
+ createHelloWorld(HELLO_WORLD_MSG1);
+ compileAotLibrary();
+ runAndCheckHelloWorld(HELLO_WORLD_MSG1);
+ createHelloWorld(HELLO_WORLD_MSG2);
+ runAndCheckHelloWorld(HELLO_WORLD_MSG2);
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/verification/vmflags/BasicFlagsChange.java b/test/hotspot/jtreg/compiler/aot/verification/vmflags/BasicFlagsChange.java
new file mode 100644
index 000000000..c0eefb5f9
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/verification/vmflags/BasicFlagsChange.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot.verification.vmflags;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.Utils;
+import compiler.aot.HelloWorldPrinter;
+import compiler.aot.AotCompiler;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A class with common launch and check logic for testing vm flags change
+ */
+public class BasicFlagsChange {
+ private static final boolean CAN_LOAD = true;
+ /**
+ * A main method which parse arguments, expecting vm option name to
+ * be present, launch java process with combinations of provided flag
+ * enabled/disable in aot library and vm flag expecting different flag
+ * values in library and vm to be negative cases
+ * @param args should have true/false treated as "loadAlways" for
+ * tracked/non-tracked options and vm option name
+ */
+ public static void main(String args[]) {
+ if (args.length != 2) {
+ throw new Error("TESTBUG: Unexpected number of arguments: "
+ + args.length);
+ }
+ if (!"false".equals(args[0]) && !"true".equals(args[0])) {
+ throw new Error("TESTBUG: unexpected value of 1st parameter: "
+ + args[0]);
+ }
+ boolean loadAlways = Boolean.parseBoolean(args[0]);
+ String optName = args[1];
+ String optEnabled = "-XX:+" + optName;
+ String optDisabled = "-XX:-" + optName;
+ String enabledLibName = "libEnabled.so";
+ String disabledLibName = "libDisabled.so";
+ // compile libraries
+ compileLibrary(optEnabled, enabledLibName);
+ compileLibrary(optDisabled, disabledLibName);
+ // run 4 combinations
+ runAndCheck(optEnabled, enabledLibName, CAN_LOAD || loadAlways);
+ runAndCheck(optDisabled, enabledLibName, !CAN_LOAD || loadAlways);
+ runAndCheck(optEnabled, disabledLibName, !CAN_LOAD || loadAlways);
+ runAndCheck(optDisabled, disabledLibName, CAN_LOAD || loadAlways);
+ }
+
+ private static void compileLibrary(String option, String libName) {
+ String className = BasicFlagsChange.class.getName();
+ List<String> extraOpts = new ArrayList<>();
+ extraOpts.add(option);
+ extraOpts.add("-classpath");
+ extraOpts.add(Utils.TEST_CLASS_PATH + File.pathSeparator + Utils.TEST_SRC);
+ AotCompiler.launchCompiler(libName, className, extraOpts, null);
+ }
+
+ private static void runAndCheck(String option, String libName,
+ boolean positiveCase) {
+ ProcessBuilder pb;
+ try {
+ /* using +PrintAOT to check if library has been loaded or skipped,
+ so, a message like "skipped $pathTolibrary aot library" or
+ "loaded $pathToLibrary aot library" is present for cases of
+ incompatible or compatible flags respectively */
+ pb = ProcessTools.createTestJvm("-XX:+UnlockExperimentalVMOptions",
+ "-XX:+UseAOT", "-XX:+PrintAOT", "-XX:AOTLibrary=./" + libName, option,
+ HelloWorldPrinter.class.getName());
+ } catch (Exception ex) {
+ throw new Error("Problems creating ProcessBuilder using " + option
+ + " Caused by: " + ex, ex);
+ }
+ OutputAnalyzer oa;
+ try {
+ oa = ProcessTools.executeProcess(pb);
+ } catch (Exception ex) {
+ throw new Error("Problems execution child process using case "
+ + option + " Caused by: " + ex, ex);
+ }
+ oa.shouldHaveExitValue(0);
+ oa.shouldContain(HelloWorldPrinter.MESSAGE);
+ if (positiveCase) {
+ oa.shouldContain("loaded ./" + libName + " aot library");
+ } else {
+ oa.shouldContain("skipped ./" + libName + " aot library");
+ }
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/aot/verification/vmflags/NotTrackedFlagTest.java b/test/hotspot/jtreg/compiler/aot/verification/vmflags/NotTrackedFlagTest.java
new file mode 100644
index 000000000..306e7d9e6
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/verification/vmflags/NotTrackedFlagTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.verification.vmflags.BasicFlagsChange
+ * @run driver compiler.aot.verification.vmflags.BasicFlagsChange
+ * true PrintCommandLineFlags
+ * @summary check if some not aot-related vm flag change doesn't affect aot library loading
+ */
diff --git a/test/hotspot/jtreg/compiler/aot/verification/vmflags/TrackedFlagTest.java b/test/hotspot/jtreg/compiler/aot/verification/vmflags/TrackedFlagTest.java
new file mode 100644
index 000000000..382399a05
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/aot/verification/vmflags/TrackedFlagTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @requires vm.aot
+ * @library /test/lib /
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.verification.vmflags.BasicFlagsChange
+ * @run driver compiler.aot.verification.vmflags.BasicFlagsChange
+ * false UseCompressedOops
+ * @summary check if tracked flag UseCompressedOops is controlled properly
+ */
+
diff --git a/test/hotspot/jtreg/compiler/intrinsics/bigInteger/TestMulAdd.java b/test/hotspot/jtreg/compiler/intrinsics/bigInteger/TestMulAdd.java
index f72cc8cb5..14942dfa5 100644
--- a/test/hotspot/jtreg/compiler/intrinsics/bigInteger/TestMulAdd.java
+++ b/test/hotspot/jtreg/compiler/intrinsics/bigInteger/TestMulAdd.java
@@ -26,6 +26,8 @@
* @key randomness
* @bug 8081778
* @summary Add C2 x86 intrinsic for BigInteger::mulAdd() method
+ * @comment the test disables intrinsics, so it can't be run w/ AOT'ed java.base
+ * @requires !vm.aot.enabled
*
* @library /test/lib
* @run main/othervm/timeout=600 -XX:-TieredCompilation -Xbatch
diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestMD5Intrinsics.java b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestMD5Intrinsics.java
index 16f2b6cc5..db165cc56 100644
--- a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestMD5Intrinsics.java
+++ b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestMD5Intrinsics.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
* @test
* @bug 8035968
* @summary Verify that MD5 intrinsic is actually used.
+ * @comment the test verifies compilation of java.base methods, so it can't be run w/ AOT'ed java.base
+ * @requires !vm.aot.enabled
*
* @library /test/lib /
* @modules java.base/jdk.internal.misc
diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestMD5MultiBlockIntrinsics.java b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestMD5MultiBlockIntrinsics.java
index d6c9006ee..b9473ea91 100644
--- a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestMD5MultiBlockIntrinsics.java
+++ b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestMD5MultiBlockIntrinsics.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
* @test
* @bug 8035968
* @summary Verify that MD5 multi block intrinsic is actually used.
+ * @comment the test verifies compilation of java.base methods, so it can't be run w/ AOT'ed java.base
+ * @requires !vm.aot.enabled
*
* @library /test/lib /
* @modules java.base/jdk.internal.misc
diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA1Intrinsics.java b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA1Intrinsics.java
index 5a756a6ec..ca3d5751f 100644
--- a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA1Intrinsics.java
+++ b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA1Intrinsics.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
* @test
* @bug 8035968
* @summary Verify that SHA-1 intrinsic is actually used.
+ * @comment the test verifies compilation of java.base methods, so it can't be run w/ AOT'ed java.base
+ * @requires !vm.aot.enabled
*
* @library /test/lib /
* @modules java.base/jdk.internal.misc
diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA1MultiBlockIntrinsics.java b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA1MultiBlockIntrinsics.java
index 415bbe6ec..753dcdb48 100644
--- a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA1MultiBlockIntrinsics.java
+++ b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA1MultiBlockIntrinsics.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
* @test
* @bug 8035968
* @summary Verify that SHA-1 multi block intrinsic is actually used.
+ * @comment the test verifies compilation of java.base methods, so it can't be run w/ AOT'ed java.base
+ * @requires !vm.aot.enabled
*
* @library /test/lib /
* @modules java.base/jdk.internal.misc
diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA256Intrinsics.java b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA256Intrinsics.java
index 607a48a45..7567aadac 100644
--- a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA256Intrinsics.java
+++ b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA256Intrinsics.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
* @test
* @bug 8035968
* @summary Verify that SHA-256 intrinsic is actually used.
+ * @comment the test verifies compilation of java.base methods, so it can't be run w/ AOT'ed java.base
+ * @requires !vm.aot.enabled
*
* @library /test/lib /
* @modules java.base/jdk.internal.misc
diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA256MultiBlockIntrinsics.java b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA256MultiBlockIntrinsics.java
index a1200d183..c3d01e8f2 100644
--- a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA256MultiBlockIntrinsics.java
+++ b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA256MultiBlockIntrinsics.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
* @test
* @bug 8035968
* @summary Verify that SHA-256 multi block intrinsic is actually used.
+ * @comment the test verifies compilation of java.base methods, so it can't be run w/ AOT'ed java.base
+ * @requires !vm.aot.enabled
*
* @library /test/lib /
* @modules java.base/jdk.internal.misc
diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA3Intrinsics.java b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA3Intrinsics.java
index df90a545d..892d1a8a4 100644
--- a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA3Intrinsics.java
+++ b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA3Intrinsics.java
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2020, Huawei Technologies Co., Ltd. All rights reserved.
+ * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,8 @@
* @test
* @bug 8252204
* @summary Verify that SHA3-224, SHA3-256, SHA3-384, SHA3-512 intrinsic is actually used.
+ * @comment the test verifies compilation of java.base methods, so it can't be run w/ AOT'ed java.base
+ * @requires !vm.aot.enabled
*
* @library /test/lib /
* @modules java.base/jdk.internal.misc
diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA3MultiBlockIntrinsics.java b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA3MultiBlockIntrinsics.java
index 1e01b543f..53eafe3ce 100644
--- a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA3MultiBlockIntrinsics.java
+++ b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA3MultiBlockIntrinsics.java
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2020, Huawei Technologies Co., Ltd. All rights reserved.
+ * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,8 @@
* @test
* @bug 8252204
* @summary Verify that SHA3-224, SHA3-256, SHA3-384, SHA3-512 multi block intrinsic is actually used.
+ * @comment the test verifies compilation of java.base methods, so it can't be run w/ AOT'ed java.base
+ * @requires !vm.aot.enabled
*
* @library /test/lib /
* @modules java.base/jdk.internal.misc
diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA512Intrinsics.java b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA512Intrinsics.java
index 2a5f9bf09..259d6cf99 100644
--- a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA512Intrinsics.java
+++ b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA512Intrinsics.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
* @test
* @bug 8035968
* @summary Verify that SHA-512 intrinsic is actually used.
+ * @comment the test verifies compilation of java.base methods, so it can't be run w/ AOT'ed java.base
+ * @requires !vm.aot.enabled
*
* @library /test/lib /
* @modules java.base/jdk.internal.misc
diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA512MultiBlockIntrinsics.java b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA512MultiBlockIntrinsics.java
index 5caf35f23..12583507f 100644
--- a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA512MultiBlockIntrinsics.java
+++ b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/TestSHA512MultiBlockIntrinsics.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
* @test
* @bug 8035968
* @summary Verify that SHA-512 multi block intrinsic is actually used.
+ * @comment the test verifies compilation of java.base methods, so it can't be run w/ AOT'ed java.base
+ * @requires !vm.aot.enabled
*
* @library /test/lib /
* @modules java.base/jdk.internal.misc
diff --git a/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java b/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java
index 407aac786..30bb71236 100644
--- a/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java
+++ b/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -41,6 +41,8 @@ import java.util.function.Function;
public abstract class CompilerWhiteBoxTest {
/** {@code CompLevel::CompLevel_none} -- Interpreter */
public static final int COMP_LEVEL_NONE = 0;
+ /** {@code CompLevel::CompLevel_aot} -- AOT */
+ public static final int COMP_LEVEL_AOT = -2;
/** {@code CompLevel::CompLevel_any}, {@code CompLevel::CompLevel_all} */
public static final int COMP_LEVEL_ANY = -1;
/** {@code CompLevel::CompLevel_simple} -- C1 */
diff --git a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java
index 8e2033e73..ccbaddeb5 100644
--- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java
+++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -94,6 +94,7 @@ public class CompressedClassPointers {
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+UnlockExperimentalVMOptions",
"-Xmx30g",
+ "-XX:-UseAOT", // AOT explicitly set klass shift to 3.
logging_option,
"-Xshare:off",
"-XX:+VerifyBeforeGC", "-version");
@@ -119,6 +120,7 @@ public class CompressedClassPointers {
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+UnlockExperimentalVMOptions",
"-Xmx31g",
+ "-XX:-UseAOT", // AOT explicitly set klass shift to 3.
logging_option,
"-Xshare:off",
"-XX:+VerifyBeforeGC", "-version");
@@ -238,6 +240,7 @@ public class CompressedClassPointers {
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+UnlockExperimentalVMOptions",
"-Xmx30g",
+ "-XX:-UseAOT", // AOT explicitly set klass shift to 3.
"-Xlog:gc+metaspace=trace",
"-Xshare:off",
"-Xlog:cds=trace",
diff --git a/test/hotspot/jtreg/runtime/cds/TestInterpreterMethodEntries.java b/test/hotspot/jtreg/runtime/cds/TestInterpreterMethodEntries.java
index a29432f36..e258ee8c3 100644
--- a/test/hotspot/jtreg/runtime/cds/TestInterpreterMethodEntries.java
+++ b/test/hotspot/jtreg/runtime/cds/TestInterpreterMethodEntries.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,8 @@
* @summary Test interpreter method entries for intrinsics with CDS (class data sharing)
* and the intrinsic flag enabled during dump and disabled during use of the archive.
* @requires vm.cds
+ * @comment the test disables intrinsics, so it can't be run w/ AOT'ed java module
+ * @requires !vm.aot.enabled
* @library /test/lib
* @run driver TestInterpreterMethodEntries true false
*/
diff --git a/test/hotspot/jtreg/serviceability/dcmd/compiler/CodelistTest.java b/test/hotspot/jtreg/serviceability/dcmd/compiler/CodelistTest.java
index 260de5c1e..c93d943f4 100644
--- a/test/hotspot/jtreg/serviceability/dcmd/compiler/CodelistTest.java
+++ b/test/hotspot/jtreg/serviceability/dcmd/compiler/CodelistTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -120,7 +120,7 @@ public class CodelistTest {
Assert.assertTrue(compileID > 0, "CompileID must be positive");
int compileLevel = Integer.parseInt(parts[1]);
- Assert.assertTrue(compileLevel >= -1, "CompileLevel must be at least -1 (Any)");
+ Assert.assertTrue(compileLevel >= -1, "CompileLevel must be at least -1 (AOT)");
Assert.assertTrue(compileLevel <= 4, "CompileLevel must be at most 4 (C2)");
int codeState = Integer.parseInt(parts[2]);
diff --git a/test/hotspot/jtreg/testlibrary/jittester/Makefile b/test/hotspot/jtreg/testlibrary/jittester/Makefile
index 32548e6cd..fdc34fe69 100644
--- a/test/hotspot/jtreg/testlibrary/jittester/Makefile
+++ b/test/hotspot/jtreg/testlibrary/jittester/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -108,7 +108,7 @@ filelist: $(SRC_FILES)
INIT: $(DIST_DIR)
$(shell if [ ! -d $(CLASSES_DIR) ]; then mkdir -p $(CLASSES_DIR); fi)
-install: clean_testbase testgroup testroot copytestlibrary $(DIST_JAR) cleantmp
+install: clean_testbase testgroup testroot copytestlibrary copyaot $(DIST_JAR) cleantmp
$(JAVA) --add-exports=java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED -ea -jar $(DIST_JAR) $(APPLICATION_ARGS)
clean_testbase:
@@ -122,6 +122,9 @@ copytestlibrary: $(TESTBASE_DIR)/jdk/test/lib/jittester/jtreg
@cp -r src/jdk/test/lib/jittester/jtreg/*.java $(TESTBASE_DIR)/jdk/test/lib/jittester/jtreg
@cp -r $(TESTLIBRARY_SRC_DIR) $(TESTBASE_DIR)/jdk/test/
+copyaot: $(TESTBASE_DIR)/compiler/aot
+ @cp ../../compiler/aot/AotCompiler.java $(TESTBASE_DIR)/compiler/aot
+
testgroup: $(TESTBASE_DIR)
@echo 'jittester_all = \' > $(TESTGROUP_FILE)
@echo ' /' >> $(TESTGROUP_FILE)
@@ -130,9 +133,13 @@ testgroup: $(TESTBASE_DIR)
@echo ' java_tests \' >> $(TESTGROUP_FILE)
@echo ' bytecode_tests' >> $(TESTGROUP_FILE)
@echo '' >> $(TESTGROUP_FILE)
+ @echo 'aot_tests = \' >> $(TESTGROUP_FILE)
+ @echo ' aot_bytecode_tests \' >> $(TESTGROUP_FILE)
+ @echo ' aot_java_tests' >> $(TESTGROUP_FILE)
+ @echo '' >> $(TESTGROUP_FILE)
testroot: $(TESTBASE_DIR)
@echo 'groups=TEST.groups' > $(TESTROOT_FILE)
-$(TESTBASE_DIR) $(DIST_DIR) $(TESTBASE_DIR)/jdk/test/lib/jittester/jtreg:
+$(TESTBASE_DIR) $(DIST_DIR) $(TESTBASE_DIR)/jdk/test/lib/jittester/jtreg $(TESTBASE_DIR)/compiler/aot:
$(shell if [ ! -d $@ ]; then mkdir -p $@; fi)
diff --git a/test/hotspot/jtreg/testlibrary/jittester/conf/default.properties b/test/hotspot/jtreg/testlibrary/jittester/conf/default.properties
index cd559e591..0573cc1d4 100644
--- a/test/hotspot/jtreg/testlibrary/jittester/conf/default.properties
+++ b/test/hotspot/jtreg/testlibrary/jittester/conf/default.properties
@@ -9,5 +9,5 @@ exclude-methods-file=conf/exclude.methods.lst
print-complexity=true
print-hierarchy=true
disable-static=true
-generatorsFactories=jdk.test.lib.jittester.TestGeneratorsFactory
+generatorsFactories=jdk.test.lib.jittester.TestGeneratorsFactory,jdk.test.lib.jittester.AotTestGeneratorsFactory
generators=JavaCode,ByteCode
diff --git a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/AotTestGeneratorsFactory.java b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/AotTestGeneratorsFactory.java
new file mode 100644
index 000000000..2f0db9a7e
--- /dev/null
+++ b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/AotTestGeneratorsFactory.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.jittester;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+public class AotTestGeneratorsFactory implements Function<String[], List<TestsGenerator>> {
+ private static final String AOT_OPTIONS
+ = "-XX:+UnlockExperimentalVMOptions -XX:+UseAOT -XX:AOTLibrary=./aottest.so";
+ private static final String AOT_COMPILER_BUILD_ACTION
+ = "@build compiler.aot.AotCompiler";
+ private static final String AOT_COMPILER_RUN_ACTION_PREFIX
+ = "@run driver compiler.aot.AotCompiler -extraopt -Xmixed -libname aottest.so -class ";
+
+ @Override
+ public List<TestsGenerator> apply(String[] input) {
+ List<TestsGenerator> result = new ArrayList<>();
+ for (String generatorName : input) {
+ switch (generatorName) {
+ case "ByteCode":
+ result.add(new ByteCodeGenerator("aot_bytecode_tests",
+ AotTestGeneratorsFactory::generateBytecodeHeader, AOT_OPTIONS));
+ break;
+ case "JavaCode":
+ result.add(new JavaCodeGenerator("aot_java_tests",
+ AotTestGeneratorsFactory::generateJavaHeader, AOT_OPTIONS));
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown generator: " + generatorName);
+ }
+ }
+ return result;
+ }
+
+ private static String[] generateBytecodeHeader(String mainClassName) {
+ return new String[]{
+ AOT_COMPILER_BUILD_ACTION,
+ AOT_COMPILER_RUN_ACTION_PREFIX + mainClassName
+ };
+ }
+
+ private static String[] generateJavaHeader(String mainClassName) {
+ return new String[]{
+ "@compile " + mainClassName + ".java",
+ AOT_COMPILER_BUILD_ACTION,
+ AOT_COMPILER_RUN_ACTION_PREFIX + mainClassName
+ };
+ }
+}
diff --git a/test/hotspot/jtreg/vmTestbase/vm/compiler/CodeCacheInfo/Test.java b/test/hotspot/jtreg/vmTestbase/vm/compiler/CodeCacheInfo/Test.java
index 118d6c8f8..a3cc54cfd 100644
--- a/test/hotspot/jtreg/vmTestbase/vm/compiler/CodeCacheInfo/Test.java
+++ b/test/hotspot/jtreg/vmTestbase/vm/compiler/CodeCacheInfo/Test.java
@@ -62,6 +62,15 @@ public class Test {
String segPrefix = "^(CodeHeap '[^']+':" + p1 + p2 + ")+";
String nosegPrefix = "^CodeCache:" + p1 + p2;
+ // check if AOT is enabled
+ if (WhiteBox.getWhiteBox().aotLibrariesCount() > 0) {
+ System.out.println("AOT is enabled");
+ String aotSegment = "CodeHeap 'AOT':" + p1 + p2;
+ segPrefix += aotSegment;
+ nosegPrefix += aotSegment;
+ } else {
+ System.out.println("AOT is not enabled");
+ }
SEG_REGEXP = segPrefix + p3 + p4;
NOSEG_REGEXP = nosegPrefix + p3 + p4;
}
diff --git a/test/jdk/ProblemList-aot.txt b/test/jdk/ProblemList-aot.txt
new file mode 100644
index 000000000..722f4c9e3
--- /dev/null
+++ b/test/jdk/ProblemList-aot.txt
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+#############################################################################
+#
+# List of quarantined tests for testing AOT.
+#
+#############################################################################
+
+java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java 8222445 windows-x64
+java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java 8222445 windows-x64
+java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java 8222445 windows-x64
+java/lang/reflect/PublicMethods/PublicMethodsTest.java 8226309 generic-all
+java/lang/constant/MethodTypeDescTest.java 8225349 windows-x64
diff --git a/test/jdk/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java b/test/jdk/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java
index 12cab1f5d..7c647d6d4 100644
--- a/test/jdk/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java
+++ b/test/jdk/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java
@@ -312,8 +312,8 @@ public class FieldSetAccessibleTest {
Set<String> mods = Set.of(
// All JVMCI packages other than jdk.vm.ci.services are dynamically
- // exported to jdk.internal.vm.compiler
- "jdk.internal.vm.compiler", "jdk.internal.vm.compiler.management"
+ // exported to jdk.internal.vm.compiler and jdk.aot
+ "jdk.internal.vm.compiler", "jdk.internal.vm.compiler.management", "jdk.aot"
);
// Filters all modules that directly or indirectly require jdk.internal.vm.compiler
// and jdk.internal.vm.compiler.management, as these are upgradeable and
diff --git a/test/jdk/jdk/modules/etc/UpgradeableModules.java b/test/jdk/jdk/modules/etc/UpgradeableModules.java
index 59ff5aa6b..a7e467b50 100644
--- a/test/jdk/jdk/modules/etc/UpgradeableModules.java
+++ b/test/jdk/jdk/modules/etc/UpgradeableModules.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -44,6 +44,7 @@ import java.util.stream.Collectors;
public class UpgradeableModules {
private static final List<String> UPGRADEABLE_MODULES =
List.of("java.compiler",
+ "jdk.aot",
"jdk.internal.vm.compiler",
"jdk.internal.vm.compiler.management");
diff --git a/test/jdk/tools/jimage/VerifyJimage.java b/test/jdk/tools/jimage/VerifyJimage.java
index 59d0a5cec..e1012d6ad 100644
--- a/test/jdk/tools/jimage/VerifyJimage.java
+++ b/test/jdk/tools/jimage/VerifyJimage.java
@@ -197,7 +197,7 @@ public class VerifyJimage {
// All JVMCI packages other than jdk.vm.ci.services are dynamically
// exported to jdk.internal.vm.compiler
- private static Set<String> EXCLUDED_MODULES = Set.of("jdk.internal.vm.compiler");
+ private static Set<String> EXCLUDED_MODULES = Set.of("jdk.internal.vm.compiler", "jdk.aot");
private boolean accept(String entry) {
int index = entry.indexOf('/', 1);
diff --git a/test/jdk/tools/launcher/HelpFlagsTest.java b/test/jdk/tools/launcher/HelpFlagsTest.java
index 62405855d..f7a4acd0c 100644
--- a/test/jdk/tools/launcher/HelpFlagsTest.java
+++ b/test/jdk/tools/launcher/HelpFlagsTest.java
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2018, 2020 SAP SE. All rights reserved.
+ * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2023 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -122,6 +122,7 @@ public class HelpFlagsTest extends TestHelper {
// of help docu of wrong
// mented flag
new ToolHelpSpec("jabswitch", 0, 0, 0, 0, 0, 0, 0), // /?, prints help message anyways, win only
+ new ToolHelpSpec("jaotc", 1, 1, 1, 0, 0, 0, 2), // -?, -h, --help
new ToolHelpSpec("jar", 1, 1, 1, 0, 0, 0, 1), // -?, -h, --help
new ToolHelpSpec("jarsigner", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented.
new ToolHelpSpec("java", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help
diff --git a/test/jdk/tools/launcher/VersionCheck.java b/test/jdk/tools/launcher/VersionCheck.java
index c5b488d76..1fd5dd99a 100644
--- a/test/jdk/tools/launcher/VersionCheck.java
+++ b/test/jdk/tools/launcher/VersionCheck.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -54,6 +54,7 @@ public class VersionCheck extends TestHelper {
"jaccessinspector-32",
"jaccesswalker",
"jaccesswalker-32",
+ "jaotc",
"javaw",
"javaws",
"jbooster",
@@ -73,6 +74,7 @@ public class VersionCheck extends TestHelper {
"jaccessinspector-32",
"jaccesswalker",
"jaccesswalker-32",
+ "jaotc",
"jar",
"jarsigner",
"java-rmi",
diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java
index 452f3c9dc..e696966b5 100644
--- a/test/jtreg-ext/requires/VMProps.java
+++ b/test/jtreg-ext/requires/VMProps.java
@@ -112,6 +112,8 @@ public class VMProps implements Callable<Map<String, String>> {
map.put("vm.pageSize", this::vmPageSize);
map.put("vm.rtm.cpu", this::vmRTMCPU);
map.put("vm.rtm.compiler", this::vmRTMCompiler);
+ map.put("vm.aot", this::vmAOT);
+ map.put("vm.aot.enabled", this::vmAotEnabled);
// vm.cds is true if the VM is compiled with cds support.
map.put("vm.cds", this::vmCDS);
map.put("vm.cds.custom.loaders", this::vmCDSForCustomLoaders);
@@ -372,6 +374,46 @@ public class VMProps implements Callable<Map<String, String>> {
return "" + CPUInfo.hasFeature("rtm");
}
+ /**
+ * @return true if VM supports AOT and false otherwise
+ */
+ protected String vmAOT() {
+ // builds with aot have jaotc in <JDK>/bin
+ Path bin = Paths.get(System.getProperty("java.home"))
+ .resolve("bin");
+ Path jaotc;
+ if (Platform.isWindows()) {
+ jaotc = bin.resolve("jaotc.exe");
+ } else {
+ jaotc = bin.resolve("jaotc");
+ }
+
+ if (!Files.exists(jaotc)) {
+ // No jaotc => no AOT
+ return "false";
+ }
+
+ switch (GC.selected()) {
+ case Serial:
+ case Parallel:
+ case G1:
+ // These GCs are supported with AOT
+ return "true";
+ default:
+ break;
+ }
+
+ // Every other GC is not supported
+ return "false";
+ }
+
+ /*
+ * @return true if there is at least one loaded AOT'ed library.
+ */
+ protected String vmAotEnabled() {
+ return "" + (WB.aotLibrariesCount() > 0);
+ }
+
/**
* Check for CDS support.
*
diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java
index 5a0ab744a..55972aa1b 100644
--- a/test/lib/jdk/test/whitebox/WhiteBox.java
+++ b/test/lib/jdk/test/whitebox/WhiteBox.java
@@ -638,6 +638,9 @@ public class WhiteBox {
// Protection Domain Table
public native int protectionDomainRemovedCount();
+ // Number of loaded AOT libraries
+ public native int aotLibrariesCount();
+
public native int getKlassMetadataSize(Class<?> c);
// ThreadSMR GC safety check for threadObj
diff --git a/test/lib/jdk/test/whitebox/code/CodeBlob.java b/test/lib/jdk/test/whitebox/code/CodeBlob.java
index c6c23fdff..2b99a9a2f 100644
--- a/test/lib/jdk/test/whitebox/code/CodeBlob.java
+++ b/test/lib/jdk/test/whitebox/code/CodeBlob.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -50,8 +50,12 @@ public class CodeBlob {
name = (String) obj[0];
size = (Integer) obj[1];
int blob_type_index = (Integer) obj[2];
- code_blob_type = BlobType.values()[blob_type_index];
- assert code_blob_type.id == (Integer) obj[2];
+ if (blob_type_index == -1) { // AOT
+ code_blob_type = null;
+ } else {
+ code_blob_type = BlobType.values()[blob_type_index];
+ assert code_blob_type.id == (Integer) obj[2];
+ }
address = (Long) obj[3];
}
public final String name;
--
2.19.1