--- 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 @@ -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 @@ -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, \ STRING_KEYWORDS := OPTIONS JAVA_OPTIONS VM_OPTIONS KEYWORDS \ - EXTRA_PROBLEM_LISTS LAUNCHER_OPTIONS, \ + EXTRA_PROBLEM_LISTS AOT_MODULES LAUNCHER_OPTIONS, \ )) ifneq ($(JTREG), ) @@ -214,10 +305,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), ) @@ -498,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)) @@ -509,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) \ @@ -844,6 +943,17 @@ define SetupRunJtregTestBody endif endif + 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) @@ -891,7 +1001,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* libraries = AOTLoader::libraries(); + for (GrowableArrayIterator 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: "Ljava/lang/ThreadGroup;addUnstarted()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:") 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 { + 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 + +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 { +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" for stub, + // For nmethod: "Ljava/lang/ThreadGroup;addUnstarted()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::operator new; + using CHeapObj::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* AOTLoader::_heaps = new(ResourceObj::C_HEAP, mtCode) GrowableArray (2, mtCode); +GrowableArray* AOTLoader::_libraries = new(ResourceObj::C_HEAP, mtCode) GrowableArray (2, mtCode); + +// Iterate over all AOT CodeHeaps +#define FOR_ALL_AOT_HEAPS(heap) for (GrowableArrayIterator heap = heaps()->begin(); heap != heaps()->end(); ++heap) +// Iterate over all AOT Libraries +#define FOR_ALL_AOT_LIBRARIES(lib) for (GrowableArrayIterator 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 GrowableArray; +class InstanceKlass; +class JavaThread; +class Metadata; +class OopClosure; + +class AOTLoader { +private: +#if INCLUDE_AOT + static GrowableArray* _heaps; + static GrowableArray* _libraries; +#endif + static void load_library(const char* name, bool exit_on_error); + +public: +#if INCLUDE_AOT + static GrowableArray* heaps(); + static GrowableArray* 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* AOTLoader::heaps() { return _heaps; } +GrowableArray* 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(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(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("ThreadRoots", "Thread Roots (ms):", max_gc_threads); _gc_par_phases[CLDGRoots] = new WorkerDataArray("CLDGRoots", "CLDG Roots (ms):", max_gc_threads); + AOT_ONLY(_gc_par_phases[AOTCodeRoots] = new WorkerDataArray("AOTCodeRoots", "AOT Root Scan (ms):", max_gc_threads);) _gc_par_phases[CMRefRoots] = new WorkerDataArray("CMRefRoots", "CM RefProcessor Roots (ms):", max_gc_threads); for (auto id : EnumRange()) { 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 { 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()) { 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 @@ -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 RootSetClosure::RootSetClosure(Delegate* delegate) : _delegate(delegate) {} @@ -71,6 +74,9 @@ void RootSetClosure::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; 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().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 . + } + + 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 . + 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(); +} + +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* _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 { // 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* 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* VM_RedefineClasses::_old_methods = NULL; Array* 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 class BoxCacheBase : public CHeapObj { 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* 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* 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* 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(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 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 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. + * + *

+ * 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. + * + *

+ * 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. + * + *

+ * 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 offsetStringTable = new HashMap<>(); + + private final Map metaspaceNames = new HashMap<>(); + + // List of relocation table entries - (symbolName, relocationInfo) + private final Map symbolTable = new HashMap<>(); + private final Map> relocationTable = new HashMap<>(); + private final Map uniqueRelocationTable = new HashMap<>(); + + /** + * Mapping of local VM function names to known global symbols generated in the output binary. + */ + private static final HashMap 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 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 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 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 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 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: + // "Ljava/lang/ThreadGroup;addUnstarted()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 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__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__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> relocEntries; + + ElfRelocTable(int numsects) { + relocEntries = new ArrayList<>(numsects); + for (int i = 0; i < numsects; i++) { + relocEntries.add(new ArrayList()); + } + } + + 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 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 localSymbols = new ArrayList<>(); + private final ArrayList 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 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 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 sections, CodeContainer c) { + createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_EXECINSTR); + } + + private void createReadOnlySection(ArrayList sections, ReadOnlyDataContainer c) { + createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC); + } + + private void createReadWriteSection(ArrayList 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> relocationTable, Collection symbols) throws IOException { + // Allocate ELF Header + ElfHeader eh = new ElfHeader(); + + ArrayList 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 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 sections, + Map> relocationTable) { + + ElfRelocTable elfRelocTable = new ElfRelocTable(sections.size()); + /* + * For each of the symbols with associated relocation records, create a Elf relocation + * entry. + */ + for (Map.Entry> entry : relocationTable.entrySet()) { + List relocs = entry.getValue(); + Symbol symbol = entry.getKey(); + + for (Relocation reloc : relocs) { + createRelocation(symbol, reloc, elfRelocTable); + } + } + + for (Map.Entry entry : binContainer.getUniqueRelocationTable().entrySet()) { + createRelocation(entry.getKey(), entry.getValue(), elfRelocTable); + } + + return (elfRelocTable); + } + + private static void createElfRelocSections(ArrayList 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 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 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 sections, ReadOnlyDataContainer c) { + createByteSection(sections, c, c.getContainerName(), "__TEXT", + section_64.S_ATTR_SOME_INSTRUCTIONS); + } + + private void createReadWriteSection(ArrayList 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> relocationTable, Collection 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 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 sections, + Collection 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 sections, + Map> 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> entry : relocationTable.entrySet()) { + List relocs = entry.getValue(); + Symbol symbol = entry.getKey(); + + for (Relocation reloc : relocs) { + createRelocation(symbol, reloc, machORelocTable); + } + } + + for (Map.Entry 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> relocEntries; + int fileOffset; + + MachORelocTable(int numsects) { + relocEntries = new ArrayList<>(numsects); + for (int i = 0; i < numsects; i++) { + relocEntries.add(new ArrayList()); + } + } + + 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 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 localSymbols = new ArrayList<>(); + private final ArrayList globalSymbols = new ArrayList<>(); + private final ArrayList 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 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 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 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 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 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> relocationTable, Collection symbols) throws IOException { + ArrayList 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 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 sections, Map> relocationTable) { + + PECoffRelocTable pecoffRelocTable = new PECoffRelocTable(sections.size()); + /* + * For each of the symbols with associated relocation records, create a PECoff relocation + * entry. + */ + for (Map.Entry> entry : relocationTable.entrySet()) { + List relocs = entry.getValue(); + Symbol symbol = entry.getKey(); + + for (Relocation reloc : relocs) { + createRelocation(symbol, reloc, pecoffRelocTable); + } + } + + for (Map.Entry 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__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> relocEntries; + + PECoffRelocTable(int numsects) { + relocEntries = new ArrayList<>(numsects); + for (int i = 0; i < numsects; i++) { + relocEntries.add(new ArrayList()); + } + } + + 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 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 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 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 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 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 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 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 consumer) { + consumer.accept("foo.Bar", new ClassLoader() { + @Override + public Class loadClass(String nm) throws ClassNotFoundException { + loaded.add(nm); + return null; + } + }); + } + }; + } + }); + + java.util.List 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 searchForList(String... entries) { + List list = new ArrayList<>(); + for (String entry : entries) { + list.add(new SearchFor(entry)); + } + return list; + } + + @SafeVarargs + private static List list(T... entries) { + List list = new ArrayList<>(); + for (T entry : entries) { + list.add(entry); + } + return list; + } + + @SafeVarargs + private static Set hashset(T... entries) { + Set set = new HashSet<>(); + for (T entry : entries) { + set.add(entry); + } + return set; + } + + private static class NoopSource implements ClassSource { + @Override + public void eachClass(BiConsumer 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 exists = new HashSet<>(); + private final Set directories = new HashSet<>(); + + private final Set checkedExists = new HashSet<>(); + private final Set checkedDirectory = new HashSet<>(); + private final Set checkedJarFileSystemRoots = new HashSet<>(); + private final Set classloaderPaths = new HashSet<>(); + + private Path jarFileSystemRoot = null; + private final ClassLoader classLoader; + + public FakeFileSupport(Set existing, Set 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 getCheckedExists() { + return checkedExists; + } + + public Set getCheckedDirectory() { + return checkedDirectory; + } + + public Set getCheckedJarFileSystemRoots() { + return checkedJarFileSystemRoots; + } + + public Set 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 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 Set set(T... entries) { + Set 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 mkpaths(String... paths) { + Set 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 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 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 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 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 initGraphBuilderSuite(HotSpotBackend backend, boolean compileWithAssertions, HotSpotInvokeDynamicPlugin inokeDynamicPlugin) { + PhaseSuite graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy(); + ListIterator> 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 { + + 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 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 locs = dynoStore.getDynamicClassLocationsForType(type); + if (locs == null) { + return new String[]{name}; + } else { + ArrayList 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 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 klassData = new HashMap<>(); + + /** + * List of all methods to be compiled. + */ + private ArrayList methods = new ArrayList<>(); + + /** + * List of all compiled class methods. + */ + private ArrayList 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 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 getMethods() { + ArrayList 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 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 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 compileClasses(List 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 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> typeMap = new HashMap<>(); + private HashMap> holderMap = new HashMap<>(); + + public Set getDynamicTypes() { + synchronized (typeMap) { + return typeMap.keySet(); + } + } + + public Set 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 void recordDynamicMapValue(HashMap> map, HotSpotResolvedObjectType type, T v) { + synchronized (map) { + HashSet 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 getDynamicClassLocationsForType(HotSpotResolvedObjectType type) { + synchronized (typeMap) { + return typeMap.get(type); + } + } + + public Set 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 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 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> collectClassesToCompile() { + Set> 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 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 collectMethodsToCompile(Set> classesToCompile, MetaAccessProvider metaAccess) { + int total = 0; + int count = 0; + List 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 compileOnlyStrings = new HashSet<>(); + private HashSet compileOnlyPatterns = new HashSet<>(); + + /** + * Set of method names that should be excluded from compilation. + */ + private HashSet excludeStrings = new HashSet<>(); + private HashSet 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 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 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 stubs = new HashMap<>(); + + /** + * List of referenced classes. + */ + private HashSet 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 classes; + + /** + * Target-independent container in which text symbols and code bytes are created. + */ + private final BinaryContainer binaryContainer; + + private static final HashMap vmAddresses = new HashMap<>(); + + DataBuilder(Main main, HotSpotHostBackend backend, List 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 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 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 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 specialClasses; + private List specialArgumentAndReturnTypes; + + private static Set> 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 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 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 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 getLines(InputStream stream) { + return new BufferedReader(new InputStreamReader(stream)).lines(); + } + + private static String getString(InputStream stream) { + Stream 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 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 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 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> 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 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 graphBuilderSuite = aotBackend.getGraphBuilderSuite(); + ListIterator> 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 + " list"); + log.println("use --help for a list of possible options"); + log.flush(); + } + + private void showHelp() { + log.println("Usage: " + PROGNAME + " 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 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 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 files = new LinkedList<>(); + String osName; + String outputName = defaultOutputName(); + String methodList; + List 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 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 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 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 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 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 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 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 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 Pass 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 providers = new ArrayList<>(); + + public void addProvider(SourceProvider provider) { + providers.add(provider); + } + + public List search(List search, SearchPath searchPath) { + return search(search, searchPath, (s, t) -> { + throw new InternalError(s + " : " + t, t); + }); + } + + public List search(List search, SearchPath searchPath, BiConsumer classLoadingErrorsHandler) { + List loaded = new ArrayList<>(); + + List 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 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 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 makeList(String type, String argument) { + List 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 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 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 implements Iterable { + private final ArrayList 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 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 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 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 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 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 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 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, {@index jaotc jaotc tool}, + * 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 { // * 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 compileList = new ArrayList<>(); + String libName = null; + List 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 extraopts, + List 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 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 args, List 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 -libname <.so name>" + + " [-compile ]* [-extraopt ]*"); + } + + // 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 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 + "." + }; + + 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 ... +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 ... +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 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 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 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 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 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 consumer) { + consumer.accept("foo.Bar", new ClassLoader() { + @Override + public Class loadClass(String name) throws ClassNotFoundException { + loaded.add(name); + return null; + } + }); + } + }; + } + }); + + java.util.List 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 searchForList(String... entries) { + List list = new ArrayList<>(); + for (String entry : entries) { + list.add(new SearchFor(entry)); + } + return list; + } + + private List list(T... entries) { + List list = new ArrayList(); + for (T entry : entries) { + list.add(entry); + } + return list; + } + + private Set hashset(T... entries) { + Set set = new HashSet(); + for (T entry : entries) { + set.add(entry); + } + return set; + } + + private static class NoopSource implements ClassSource { + @Override + public void eachClass(BiConsumer 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 exists = new HashSet<>(); + private final Set directories = new HashSet<>(); + + private final Set checkedExists = new HashSet<>(); + private final Set checkedDirectory = new HashSet<>(); + private final Set checkedJarFileSystemRoots = new HashSet<>(); + private final Set classloaderPaths = new HashSet<>(); + + private Path jarFileSystemRoot = null; + private final ClassLoader classLoader; + + public FakeFileSupport(Set existing, Set 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 getCheckedExists() { + return checkedExists; + } + + public Set getCheckedDirectory() { + return checkedDirectory; + } + + public Set getCheckedJarFileSystemRoots() { + return checkedJarFileSystemRoots; + } + + public Set 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 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 Set set(T... entries) { + Set 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 mkpaths(String... paths) { + Set 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")) { + 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 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 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 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 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> { + 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 apply(String[] input) { + List 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, 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 @@ -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 @@ -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 @@ -288,8 +288,8 @@ public class FieldSetAccessibleTest { static Set systemModules() { Set mods = Set.of("javafx.deploy", "jdk.deploy", "jdk.plugin", "jdk.javaws", // All JVMCI packages other than jdk.vm.ci.services are dynamically - // exported to jdk.internal.vm.compiler - "jdk.internal.vm.compiler" + // exported to jdk.internal.vm.compiler and jdk.aot + "jdk.internal.vm.compiler", "jdk.aot" ); return ModuleFinder.ofSystem().findAll().stream() .map(mref -> mref.descriptor().name()) 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 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 EXCLUDED_MODULES = Set.of("jdk.internal.vm.compiler"); + private static Set 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.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> { return "" + CPUInfo.hasFeature("rtm"); } + /** + * @return true if VM supports AOT and false otherwise + */ + protected String vmAOT() { + // builds with aot have jaotc in /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