diff --git a/common.json b/common.json index b1ff34e7c501..d6c2a1b88528 100644 --- a/common.json +++ b/common.json @@ -8,7 +8,7 @@ "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { - "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+23-2783", "platformspecific": true, "extrabundles": ["static-libs"]}, + "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+24-2950", "platformspecific": true, "extrabundles": ["static-libs"]}, "oraclejdk17": {"name": "jpg-jdk", "version": "17.0.7", "build_id": "jdk-17.0.7+8", "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17.0.7+4-jvmci-23.1-b02", "platformspecific": true }, @@ -45,13 +45,13 @@ "oraclejdk23": {"name": "jpg-jdk", "version": "23", "build_id": "jdk-23+37", "platformspecific": true, "extrabundles": ["static-libs"]}, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+23", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+23-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+23-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+23-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+23-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+23-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+23-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+24", "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+24-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+24-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+24-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+24-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+24-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+24-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { diff --git a/compiler/mx.compiler/mx_compiler.py b/compiler/mx.compiler/mx_compiler.py index 78042442e57d..0a11e64c7c52 100644 --- a/compiler/mx.compiler/mx_compiler.py +++ b/compiler/mx.compiler/mx_compiler.py @@ -640,7 +640,7 @@ def compiler_gate_benchmark_runner(tasks, extraVMarguments=None, prefix='', task } # Renaissance is missing the msvc redistributable on Windows [GR-50132] - if not mx.is_windows(): + if not mx.is_windows() and jdk.javaCompliance <= '21': for name in renaissance_suite.benchmarkList(bmSuiteArgs): iterations = renaissance_gate_iterations.get(name, -1) with Task(prefix + 'Renaissance:' + name, tasks, tags=GraalTags.benchmarktest, report=task_report_component) as t: diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java index abf5e70448a5..555baf10282e 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java @@ -66,7 +66,6 @@ public class GraalHotSpotVMConfig extends GraalHotSpotVMConfigAccess { GraalHotSpotVMConfig(HotSpotVMConfigStore store) { super(store); - assert narrowKlassShift <= logKlassAlignment : Assertions.errorMessageContext("narrowKlassShift", narrowKlassShift, "logKlassAlignment", logKlassAlignment); int logMinObjAlignment = logMinObjAlignment(); assert narrowOopShift <= logMinObjAlignment : Assertions.errorMessageContext("narrowOopShift", narrowOopShift, "logMinObjAlignment", logMinObjAlignment); oopEncoding = new CompressEncoding(narrowOopBase, narrowOopShift); @@ -201,6 +200,11 @@ public long gcTotalCollectionsAddress() { // Compressed Oops related values. public final boolean useCompressedOops = getFlag("UseCompressedOops", Boolean.class); public final boolean useCompressedClassPointers = getFlag("UseCompressedClassPointers", Boolean.class); + // JDK-8305895 allows storing the compressed class pointer in the upper 22 bits of the mark + // word. This runtime optimization is guarded by the flag UseCompactObjectHeaders. It depends + // on compressed class pointers, meaning that if useCompactObjectHeaders is true, + // useCompressedClassPointers is certainly true. + public final boolean useCompactObjectHeaders = getFlag("UseCompactObjectHeaders", Boolean.class, false, JDK >= 24); public final long narrowOopBase = getFieldValue("CompilerToVM::Data::Universe_narrow_oop_base", Long.class, "address"); public final int narrowOopShift = getFieldValue("CompilerToVM::Data::Universe_narrow_oop_shift", Integer.class, "int"); @@ -213,7 +217,6 @@ public final int logMinObjAlignment() { public final int narrowKlassSize = getFieldValue("CompilerToVM::Data::sizeof_narrowKlass", Integer.class, "int"); public final long narrowKlassBase = getFieldValue("CompilerToVM::Data::Universe_narrow_klass_base", Long.class, "address"); public final int narrowKlassShift = getFieldValue("CompilerToVM::Data::Universe_narrow_klass_shift", Integer.class, "int"); - public final int logKlassAlignment = getConstant("LogKlassAlignmentInBytes", Integer.class); public final int stackShadowPages = getFlag("StackShadowPages", Integer.class); public final int vmPageSize = getFieldValue("CompilerToVM::Data::vm_page_size", Integer.class, "size_t"); @@ -255,12 +258,17 @@ public final int logMinObjAlignment() { public final int arrayOopDescSize = getFieldValue("CompilerToVM::Data::sizeof_arrayOopDesc", Integer.class, "int"); + public final int arrayLengthOffsetInBytes = getFieldValue("CompilerToVM::Data::arrayOopDesc_length_offset_in_bytes", Integer.class, "int", -1, JDK >= 24); + /** * The offset of the array length word in an array object's header. *

* See {@code arrayOopDesc::length_offset_in_bytes()}. */ public final int arrayOopDescLengthOffset() { + if (JDK >= 24) { + return arrayLengthOffsetInBytes; + } return useCompressedClassPointers ? hubOffset + narrowKlassSize : arrayOopDescSize; } @@ -294,6 +302,8 @@ public final int arrayOopDescLengthOffset() { public final int threadCarrierThreadObjectOffset = getFieldOffset("JavaThread::_threadObj", Integer.class, "OopHandle"); public final int threadScopedValueCacheOffset = getFieldOffset("JavaThread::_scopedValueCache", Integer.class, "OopHandle"); + public final int javaThreadLockIDOffset = getFieldOffset("JavaThread::_lock_id", Integer.class, "int64_t", -1, JDK > 21); + public final int threadIsInVTMSTransitionOffset = getFieldOffset("JavaThread::_is_in_VTMS_transition", Integer.class, "bool"); public final int threadIsInTmpVTMSTransitionOffset = getFieldOffset("JavaThread::_is_in_tmp_VTMS_transition", Integer.class, "bool", -1, JDK == 21); public final int threadIsDisableSuspendOffset = getFieldOffset("JavaThread::_is_disable_suspend", Integer.class, "bool", -1, JDK >= 22); @@ -365,37 +375,35 @@ public int threadLastJavaFpOffset() { public final int frameInterpreterFrameSenderSpOffset = getConstant("frame::interpreter_frame_sender_sp_offset", Integer.class, 0, osArch.equals("amd64")); public final int frameInterpreterFrameLastSpOffset = getConstant("frame::interpreter_frame_last_sp_offset", Integer.class, 0, osArch.equals("amd64")); - public final int lockMaskInPlace = getConstant("markWord::lock_mask_in_place", Integer.class); + public final long markWordLockMaskInPlace = getConstant("markWord::lock_mask_in_place", Long.class); + public final long markWordHashMask = getConstant("markWord::hash_mask", Long.class); + + public final long markWordNoHashInPlace = getConstant("markWord::no_hash_in_place", Long.class); + public final long markWordNoLockInPlace = getConstant("markWord::no_lock_in_place", Long.class); + + // Mark word right shift to get identity hash code. + public final int markWordHashCodeShift = getConstant("markWord::hash_shift", Integer.class); + // Mark word right shift to get compressed klass pointer + public final int markWordKlassShift = getConstant("markWord::klass_shift", Integer.class, 0, JDK >= 24); + + // The following three constants are declared as 64 bits uintptr_t, but known to be 32 bits public final int unlockedValue = getConstant("markWord::unlocked_value", Integer.class); public final int monitorValue = getConstant("markWord::monitor_value", Integer.class); + public final int ageMaskInPlace = getConstant("markWord::age_mask_in_place", Integer.class); + public final int unusedMark = getConstant("markWord::marked_value", Integer.class, 3, JDK > 21); + // Identity hash code value when uninitialized. + public final int uninitializedIdentityHashCodeValue = getConstant("markWord::no_hash", Integer.class); // This field has no type in vmStructs.cpp - public final int objectMonitorOwner = getFieldOffset("ObjectMonitor::_owner", Integer.class, null); + public final int objectMonitorOwner = getFieldOffset("ObjectMonitor::_owner", Integer.class, JDK > 21 ? "int64_t" : null); public final int objectMonitorRecursions = getFieldOffset("ObjectMonitor::_recursions", Integer.class, "intptr_t"); public final int objectMonitorCxq = getFieldOffset("ObjectMonitor::_cxq", Integer.class, "ObjectWaiter*"); public final int objectMonitorEntryList = getFieldOffset("ObjectMonitor::_EntryList", Integer.class, "ObjectWaiter*"); - public final int objectMonitorSucc = getFieldOffset("ObjectMonitor::_succ", Integer.class, "JavaThread*"); - - public final int markWordNoHashInPlace = getConstant("markWord::no_hash_in_place", Integer.class); - public final int markWordNoLockInPlace = getConstant("markWord::no_lock_in_place", Integer.class); - - public long defaultPrototypeMarkWord() { - return this.markWordNoHashInPlace | this.markWordNoLockInPlace; - } - - /** - * Mark word right shift to get identity hash code. - */ - public final int identityHashCodeShift = getConstant("markWord::hash_shift", Integer.class); + public final int objectMonitorSucc = getFieldOffset("ObjectMonitor::_succ", Integer.class, JDK > 21 ? "int64_t" : "JavaThread*"); public final int contEntry = getFieldOffset("JavaThread::_cont_entry", Integer.class, "ContinuationEntry*", -1, JDK >= 24); public final int pinCount = getFieldOffset("ContinuationEntry::_pin_count", Integer.class, "uint32_t", -1, JDK >= 24); - /** - * Identity hash code value when uninitialized. - */ - public final int uninitializedIdentityHashCodeValue = getConstant("markWord::no_hash", Integer.class); - public final int methodCompiledEntryOffset = getFieldOffset("Method::_from_compiled_entry", Integer.class, "address"); public final int compilationLevelFullOptimization = getConstant("CompLevel_full_optimization", Integer.class); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java index 4dbfb8333b52..2c4526b52507 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java @@ -55,8 +55,8 @@ public final class JVMCIVersionCheck { private static final Map> JVMCI_MIN_VERSIONS = Map.of( "21", Map.of(DEFAULT_VENDOR_ENTRY, createLegacyVersion(23, 1, 33)), "24", Map.of( - "Oracle Corporation", createLabsJDKVersion("24+23", 1), - DEFAULT_VENDOR_ENTRY, createLabsJDKVersion("24+23", 1))); + "Oracle Corporation", createLabsJDKVersion("24+24", 1), + DEFAULT_VENDOR_ENTRY, createLabsJDKVersion("24+24", 1))); private static final int NA = 0; /** * Minimum Java release supported by Graal. diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotBackend.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotBackend.java index dd278bd30654..1c0013ba3923 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotBackend.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotBackend.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -419,15 +419,18 @@ private void emitCodePrefix(CompilationResultBuilder crb, ResolvedJavaMethod ins CallingConvention cc = regConfig.getCallingConvention(HotSpotCallingConventionType.JavaCallee, null, parameterTypes, this); Register receiver = asRegister(cc.getArgument(0)); int size = config.useCompressedClassPointers ? 32 : 64; - AArch64Address klassAddress = masm.makeAddress(size, receiver, config.hubOffset); if (config.icSpeculatedKlassOffset == Integer.MAX_VALUE) { crb.recordMark(HotSpotMarkId.UNVERIFIED_ENTRY); Register klass = rscratch1; if (config.useCompressedClassPointers) { - masm.ldr(32, klass, klassAddress); + if (config.useCompactObjectHeaders) { + ((AArch64HotSpotMacroAssembler) masm).loadCompactClassPointer(klass, receiver); + } else { + masm.ldr(size, klass, masm.makeAddress(size, receiver, config.hubOffset)); + } AArch64HotSpotMove.decodeKlassPointer(masm, klass, klass, config.getKlassEncoding()); } else { - masm.ldr(64, klass, klassAddress); + masm.ldr(size, klass, masm.makeAddress(size, receiver, config.hubOffset)); } // c1_LIRAssembler_aarch64.cpp: const Register IC_Klass = rscratch2; Register inlineCacheKlass = AArch64HotSpotRegisterConfig.inlineCacheRegister; @@ -436,7 +439,6 @@ private void emitCodePrefix(CompilationResultBuilder crb, ResolvedJavaMethod ins masm.branchConditionally(AArch64Assembler.ConditionFlag.EQ, verifiedStub); AArch64Call.directJmp(crb, masm, getForeignCalls().lookupForeignCall(IC_MISS_HANDLER)); } else { - // JDK-8322630 (removed ICStubs) Register data = AArch64HotSpotRegisterConfig.inlineCacheRegister; Register tmp1 = rscratch1; @@ -445,16 +447,24 @@ private void emitCodePrefix(CompilationResultBuilder crb, ResolvedJavaMethod ins // Size of IC check sequence checked with a guarantee below. int inlineCacheCheckSize = AArch64Call.isNearCall(icMissHandler) ? 20 : 32; + if (config.useCompactObjectHeaders) { + // Extra instruction for shifting + inlineCacheCheckSize += 4; + } masm.align(config.codeEntryAlignment, masm.position() + inlineCacheCheckSize); int startICCheck = masm.position(); crb.recordMark(HotSpotMarkId.UNVERIFIED_ENTRY); AArch64Address icSpeculatedKlass = masm.makeAddress(size, data, config.icSpeculatedKlassOffset); - masm.ldr(size, tmp1, klassAddress); + if (config.useCompactObjectHeaders) { + ((AArch64HotSpotMacroAssembler) masm).loadCompactClassPointer(tmp1, receiver); + } else { + masm.ldr(size, tmp1, masm.makeAddress(size, receiver, config.hubOffset)); + } + masm.ldr(size, tmp2, icSpeculatedKlass); masm.cmp(size, tmp1, tmp2); - masm.branchConditionally(AArch64Assembler.ConditionFlag.EQ, verifiedStub); AArch64Call.directJmp(crb, masm, icMissHandler); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotMacroAssembler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotMacroAssembler.java index 21456991370b..982013fa6d78 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotMacroAssembler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotMacroAssembler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jdk.graal.compiler.asm.aarch64.AArch64Assembler; import jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler; import jdk.graal.compiler.core.common.CompressEncoding; +import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.hotspot.GraalHotSpotVMConfig; import jdk.graal.compiler.lir.aarch64.AArch64Move; import jdk.vm.ci.aarch64.AArch64; @@ -81,23 +82,24 @@ public void verifyOop(Register value, Register tmp, Register tmp2, boolean compr cbz(compressed ? 32 : 64, value, ok); } - AArch64Address hubAddress; - int hubSize = config.useCompressedClassPointers ? 32 : 64; + Register object = value; if (compressed) { CompressEncoding encoding = config.getOopEncoding(); mov(32, tmp, value); AArch64Move.UncompressPointerOp.emitUncompressCode(this, tmp, tmp, encoding, true, heapBaseRegister, false); - hubAddress = makeAddress(hubSize, tmp, config.hubOffset); - } else { - hubAddress = makeAddress(hubSize, value, config.hubOffset); + object = tmp; } // Load the class if (config.useCompressedClassPointers) { - ldr(32, tmp, hubAddress); + if (config.useCompactObjectHeaders) { + loadCompactClassPointer(tmp, object); + } else { + ldr(32, tmp, makeAddress(32, object, config.hubOffset)); + } AArch64HotSpotMove.decodeKlassPointer(this, tmp, tmp, config.getKlassEncoding()); } else { - ldr(64, tmp, hubAddress); + ldr(64, tmp, makeAddress(64, object, config.hubOffset)); } // Klass::_super_check_offset ldr(32, tmp2, makeAddress(32, tmp, config.superCheckOffsetOffset)); @@ -127,4 +129,9 @@ public void verifyHeapBase() { } } + public void loadCompactClassPointer(Register result, Register receiver) { + GraalError.guarantee(config.useCompactObjectHeaders, "Load class pointer from markWord only when UseCompactObjectHeaders is on"); + ldr(64, result, makeAddress(64, receiver, config.markOffset)); + lsr(64, result, result, config.markWordKlassShift); + } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotBackend.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotBackend.java index 594205adfcd5..a25cac73fb79 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotBackend.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotBackend.java @@ -337,7 +337,6 @@ public void emitCodePrefix(ResolvedJavaMethod installedCodeOwner, CompilationRes JavaType[] parameterTypes = {providers.getMetaAccess().lookupJavaType(Object.class)}; CallingConvention cc = regConfig.getCallingConvention(HotSpotCallingConventionType.JavaCallee, null, parameterTypes, this); Register receiver = asRegister(cc.getArgument(0)); - AMD64Address src = new AMD64Address(receiver, config.hubOffset); int before; if (config.icSpeculatedKlassOffset == Integer.MAX_VALUE) { crb.recordMark(HotSpotMarkId.UNVERIFIED_ENTRY); @@ -347,18 +346,23 @@ public void emitCodePrefix(ResolvedJavaMethod installedCodeOwner, CompilationRes if (config.useCompressedClassPointers) { Register register = r10; Register heapBase = providers.getRegisters().getHeapBaseRegister(); - AMD64HotSpotMove.decodeKlassPointer(asm, register, heapBase, src, config); + if (config.useCompactObjectHeaders) { + ((AMD64HotSpotMacroAssembler) asm).loadCompactClassPointer(register, receiver); + } else { + asm.movl(register, new AMD64Address(receiver, config.hubOffset)); + } + AMD64HotSpotMove.decodeKlassPointer(asm, register, heapBase, config); if (config.narrowKlassBase != 0) { // The heap base register was destroyed above, so restore it if (config.narrowOopBase == 0L) { - asm.xorq(heapBase, heapBase); + asm.xorl(heapBase, heapBase); } else { asm.movq(heapBase, config.narrowOopBase); } } before = asm.cmpqAndJcc(inlineCacheKlass, register, ConditionFlag.NotEqual, null, false); } else { - before = asm.cmpqAndJcc(inlineCacheKlass, src, ConditionFlag.NotEqual, null, false); + before = asm.cmpqAndJcc(inlineCacheKlass, new AMD64Address(receiver, config.hubOffset), ConditionFlag.NotEqual, null, false); } crb.recordDirectCall(before, asm.position(), getForeignCalls().lookupForeignCall(IC_MISS_HANDLER), null); } else { @@ -376,6 +380,10 @@ public void emitCodePrefix(ResolvedJavaMethod installedCodeOwner, CompilationRes */ inlineCacheCheckSize += 3 + 3; } + if (config.useCompactObjectHeaders) { + // 4 bytes for extra shift instruction, 1 byte less for 0-displacement address + inlineCacheCheckSize += 3; + } asm.align(config.codeEntryAlignment, asm.position() + inlineCacheCheckSize); int startICCheck = asm.position(); @@ -384,10 +392,14 @@ public void emitCodePrefix(ResolvedJavaMethod installedCodeOwner, CompilationRes AMD64BaseAssembler.OperandSize size; if (config.useCompressedClassPointers) { - asm.movl(temp, src); + if (config.useCompactObjectHeaders) { + ((AMD64HotSpotMacroAssembler) asm).loadCompactClassPointer(temp, receiver); + } else { + asm.movl(temp, new AMD64Address(receiver, config.hubOffset)); + } size = AMD64BaseAssembler.OperandSize.DWORD; } else { - asm.movptr(temp, src); + asm.movptr(temp, new AMD64Address(receiver, config.hubOffset)); size = AMD64BaseAssembler.OperandSize.QWORD; } before = asm.cmpAndJcc(size, temp, icSpeculatedKlass, ConditionFlag.NotEqual, null, false); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotMacroAssembler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotMacroAssembler.java index cb5e2b831943..3af9bae71f40 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotMacroAssembler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotMacroAssembler.java @@ -29,7 +29,6 @@ import jdk.graal.compiler.asm.Label; import jdk.graal.compiler.asm.amd64.AMD64Address; -import jdk.graal.compiler.asm.amd64.AMD64Assembler; import jdk.graal.compiler.asm.amd64.AMD64MacroAssembler; import jdk.graal.compiler.core.common.CompressEncoding; import jdk.graal.compiler.core.common.NumUtil; @@ -108,25 +107,28 @@ public void verifyOop(Register value, Register tmp, Register tmp2, boolean compr if (!nonNull) { // first null check the value - testAndJcc(compressed ? DWORD : QWORD, value, value, AMD64Assembler.ConditionFlag.Zero, ok, true); + testAndJcc(compressed ? DWORD : QWORD, value, value, ConditionFlag.Zero, ok, true); } - AMD64Address hubAddress; + Register object = value; if (compressed) { CompressEncoding encoding = config.getOopEncoding(); Register heapBaseRegister = AMD64Move.UncompressPointerOp.hasBase(encoding) ? providers.getRegisters().getHeapBaseRegister() : Register.None; movq(tmp, value); AMD64Move.UncompressPointerOp.emitUncompressCode(this, tmp, encoding.getShift(), heapBaseRegister, true); - hubAddress = new AMD64Address(tmp, config.hubOffset); - } else { - hubAddress = new AMD64Address(value, config.hubOffset); + object = tmp; } - // Load the klass + // Load the klass into tmp if (config.useCompressedClassPointers) { - AMD64HotSpotMove.decodeKlassPointer(this, tmp, tmp2, hubAddress, config); + if (config.useCompactObjectHeaders) { + loadCompactClassPointer(tmp, object); + } else { + movl(tmp, new AMD64Address(object, config.hubOffset)); + } + AMD64HotSpotMove.decodeKlassPointer(this, tmp, tmp2, config); } else { - movq(tmp, hubAddress); + movq(tmp, new AMD64Address(object, config.hubOffset)); } // Klass::_super_check_offset movl(tmp2, new AMD64Address(tmp, config.superCheckOffsetOffset)); @@ -136,7 +138,7 @@ public void verifyOop(Register value, Register tmp, Register tmp2, boolean compr // Load the klass from the primary supers movq(tmp2, new AMD64Address(tmp, tmp2, Stride.S1)); // the Klass* should be equal - cmpqAndJcc(tmp2, tmp, AMD64Assembler.ConditionFlag.Equal, ok, true); + cmpqAndJcc(tmp2, tmp, ConditionFlag.Equal, ok, true); illegal(); bind(ok); } @@ -176,4 +178,10 @@ protected final int membarOffset() { public Register getZeroValueRegister() { return providers.getRegisters().getZeroValueRegister(config); } + + public void loadCompactClassPointer(Register result, Register receiver) { + GraalError.guarantee(config.useCompactObjectHeaders, "Load class pointer from markWord only when UseCompactObjectHeaders is on"); + movq(result, new AMD64Address(receiver, config.markOffset)); + shrq(result, config.markWordKlassShift); + } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotMove.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotMove.java index 09a4bd811feb..aa998cbe3a89 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotMove.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotMove.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -169,9 +169,12 @@ public AllocatableValue getResult() { } } - public static void decodeKlassPointer(AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, GraalHotSpotVMConfig config) { + /** + * Decode compressed class pointer stored in {@code register}. The content in {@code scratch} + * might be destroyed. + */ + public static void decodeKlassPointer(AMD64MacroAssembler masm, Register register, Register scratch, GraalHotSpotVMConfig config) { CompressEncoding encoding = config.getKlassEncoding(); - masm.movl(register, address); if (encoding.getShift() != 0) { masm.shlq(register, encoding.getShift()); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java index adb4c4800862..5150e20cf3a7 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java @@ -30,6 +30,11 @@ import static jdk.graal.compiler.hotspot.HotSpotGraalRuntime.HotSpotGC; import static jdk.graal.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.OSR_MIGRATION_END; import static jdk.graal.compiler.hotspot.meta.HotSpotHostForeignCallsProvider.GENERIC_ARRAYCOPY; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.COMPACT_HUB_LOCATION; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.COMPRESSED_HUB_LOCATION; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.HUB_LOCATION; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.HUB_WRITE_LOCATION; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.MARK_WORD_LOCATION; import static org.graalvm.nativeimage.ImageInfo.inImageRuntimeCode; import static org.graalvm.word.LocationIdentity.any; @@ -104,6 +109,7 @@ import jdk.graal.compiler.hotspot.replacements.arraycopy.HotSpotArraycopySnippets; import jdk.graal.compiler.hotspot.stubs.ForeignCallSnippets; import jdk.graal.compiler.hotspot.word.KlassPointer; +import jdk.graal.compiler.hotspot.word.PointerCastNode; import jdk.graal.compiler.nodes.AbstractBeginNode; import jdk.graal.compiler.nodes.AbstractDeoptimizeNode; import jdk.graal.compiler.nodes.CompressionNode.CompressionOp; @@ -134,11 +140,13 @@ import jdk.graal.compiler.nodes.calc.IntegerDivRemNode; import jdk.graal.compiler.nodes.calc.IsNullNode; import jdk.graal.compiler.nodes.calc.LeftShiftNode; +import jdk.graal.compiler.nodes.calc.NarrowNode; import jdk.graal.compiler.nodes.calc.RemNode; import jdk.graal.compiler.nodes.calc.SignedDivNode; import jdk.graal.compiler.nodes.calc.SignedFloatingIntegerDivNode; import jdk.graal.compiler.nodes.calc.SignedFloatingIntegerRemNode; import jdk.graal.compiler.nodes.calc.SignedRemNode; +import jdk.graal.compiler.nodes.calc.UnsignedRightShiftNode; import jdk.graal.compiler.nodes.debug.VerifyHeapNode; import jdk.graal.compiler.nodes.extended.BranchProbabilityNode; import jdk.graal.compiler.nodes.extended.BytecodeExceptionNode; @@ -368,7 +376,7 @@ public boolean supportsBulkClearArray(JavaKind elementKind) { @Override protected IdentityHashCodeSnippets.Templates createIdentityHashCodeSnippets(OptionValues options, Providers providers) { - return new IdentityHashCodeSnippets.Templates(new HotSpotHashCodeSnippets(), options, providers, HotSpotReplacementsUtil.MARK_WORD_LOCATION); + return new IdentityHashCodeSnippets.Templates(new HotSpotHashCodeSnippets(), options, providers, MARK_WORD_LOCATION); } public HotSpotAllocationSnippets.Templates getAllocationSnippets() { @@ -1115,21 +1123,31 @@ private ReadNode createReadVirtualMethod(StructuredGraph graph, ValueNode hub, i @Override protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, LoweringTool tool) { + GraalHotSpotVMConfig config = runtime.getVMConfig(); + if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) { return graph.unique(new LoadHubNode(tool.getStampProvider(), object)); } assert !object.isConstant() || object.isNullConstant(); KlassPointerStamp hubStamp = KlassPointerStamp.klassNonNull(); - if (runtime.getVMConfig().useCompressedClassPointers) { - hubStamp = hubStamp.compressed(runtime.getVMConfig().getKlassEncoding()); + if (config.useCompressedClassPointers) { + hubStamp = hubStamp.compressed(config.getKlassEncoding()); } - AddressNode address = createOffsetAddress(graph, object, runtime.getVMConfig().hubOffset); - LocationIdentity hubLocation = runtime.getVMConfig().useCompressedClassPointers ? HotSpotReplacementsUtil.COMPRESSED_HUB_LOCATION : HotSpotReplacementsUtil.HUB_LOCATION; + if (config.useCompactObjectHeaders) { + AddressNode address = createOffsetAddress(graph, object, config.markOffset); + FloatingReadNode memoryRead = graph.unique(new FloatingReadNode(address, COMPACT_HUB_LOCATION, null, StampFactory.forKind(JavaKind.Long), null, BarrierType.NONE)); + ValueNode rawCompressedHubWordSize = graph.addOrUnique(UnsignedRightShiftNode.create(memoryRead, ConstantNode.forInt(config.markWordKlassShift, graph), NodeView.DEFAULT)); + ValueNode rawCompressedHub = graph.addOrUnique(NarrowNode.create(rawCompressedHubWordSize, 32, NodeView.DEFAULT)); + ValueNode compressedKlassPointer = graph.addOrUnique(PointerCastNode.create(hubStamp, rawCompressedHub)); + return HotSpotCompressionNode.uncompress(graph, compressedKlassPointer, config.getKlassEncoding()); + } + AddressNode address = createOffsetAddress(graph, object, config.hubOffset); + LocationIdentity hubLocation = config.useCompressedClassPointers ? COMPRESSED_HUB_LOCATION : HUB_LOCATION; FloatingReadNode memoryRead = graph.unique(new FloatingReadNode(address, hubLocation, null, hubStamp, null, BarrierType.NONE)); - if (runtime.getVMConfig().useCompressedClassPointers) { - return HotSpotCompressionNode.uncompress(graph, memoryRead, runtime.getVMConfig().getKlassEncoding()); + if (config.useCompressedClassPointers) { + return HotSpotCompressionNode.uncompress(graph, memoryRead, config.getKlassEncoding()); } else { return memoryRead; } @@ -1137,14 +1155,16 @@ protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, Lower private WriteNode createWriteHub(StructuredGraph graph, ValueNode object, ValueNode value) { assert !object.isConstant() || object.asConstant().isDefaultForKind(); + GraalHotSpotVMConfig config = runtime.getVMConfig(); + GraalError.guarantee(!config.useCompactObjectHeaders, "Should not reach here with +UseCompactObjectHeaders"); ValueNode writeValue = value; - if (runtime.getVMConfig().useCompressedClassPointers) { - writeValue = HotSpotCompressionNode.compress(graph, value, runtime.getVMConfig().getKlassEncoding()); + if (config.useCompressedClassPointers) { + writeValue = HotSpotCompressionNode.compress(graph, value, config.getKlassEncoding()); } - AddressNode address = createOffsetAddress(graph, object, runtime.getVMConfig().hubOffset); - return graph.add(new WriteNode(address, HotSpotReplacementsUtil.HUB_WRITE_LOCATION, writeValue, BarrierType.NONE, MemoryOrderMode.PLAIN)); + AddressNode address = createOffsetAddress(graph, object, config.hubOffset); + return graph.add(new WriteNode(address, HUB_WRITE_LOCATION, writeValue, BarrierType.NONE, MemoryOrderMode.PLAIN)); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index 6c0aaf48ffe2..872c6034cf3d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -40,8 +40,12 @@ import static jdk.graal.compiler.hotspot.HotSpotBackend.SHAREDRUNTIME_NOTIFY_JVMTI_VTHREAD_UNMOUNT; import static jdk.graal.compiler.hotspot.HotSpotBackend.UPDATE_BYTES_CRC32; import static jdk.graal.compiler.hotspot.HotSpotBackend.UPDATE_BYTES_CRC32C; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.HOTSPOT_CARRIER_THREAD_OOP_HANDLE_LOCATION; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.HOTSPOT_CONTINUATION_ENTRY_PIN_COUNT; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.HOTSPOT_CURRENT_THREAD_OOP_HANDLE_LOCATION; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.HOTSPOT_JAVA_THREAD_CONT_ENTRY; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.HOTSPOT_JAVA_THREAD_SCOPED_VALUE_CACHE_HANDLE_LOCATION; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_LOCK_ID_LOCATION; import static jdk.graal.compiler.java.BytecodeParserOptions.InlineDuringParsing; import static jdk.graal.compiler.nodes.ConstantNode.forBoolean; import static jdk.graal.compiler.nodes.ProfileData.BranchProbabilityData.injected; @@ -61,6 +65,7 @@ import java.math.BigInteger; import java.util.zip.CRC32; +import org.graalvm.nativeimage.ImageInfo; import org.graalvm.word.LocationIdentity; import jdk.graal.compiler.api.directives.GraalDirectives; @@ -69,7 +74,9 @@ import jdk.graal.compiler.core.common.memory.BarrierType; import jdk.graal.compiler.core.common.memory.MemoryOrderMode; import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; +import jdk.graal.compiler.core.common.type.ObjectStamp; import jdk.graal.compiler.core.common.type.StampFactory; +import jdk.graal.compiler.core.common.type.TypeReference; import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.hotspot.GraalHotSpotVMConfig; import jdk.graal.compiler.hotspot.HotSpotBackend; @@ -78,6 +85,7 @@ import jdk.graal.compiler.hotspot.nodes.HotSpotLoadReservedReferenceNode; import jdk.graal.compiler.hotspot.nodes.HotSpotStoreReservedReferenceNode; import jdk.graal.compiler.hotspot.nodes.KlassFullyInitializedCheckNode; +import jdk.graal.compiler.hotspot.nodes.VirtualThreadUpdateJFRNode; import jdk.graal.compiler.hotspot.replacements.CallSiteTargetNode; import jdk.graal.compiler.hotspot.replacements.DigestBaseSnippets; import jdk.graal.compiler.hotspot.replacements.FastNotifyNode; @@ -142,6 +150,8 @@ import jdk.graal.compiler.nodes.java.DynamicNewInstanceWithExceptionNode; import jdk.graal.compiler.nodes.java.NewArrayNode; import jdk.graal.compiler.nodes.java.ValidateNewInstanceClassNode; +import jdk.graal.compiler.nodes.memory.ReadNode; +import jdk.graal.compiler.nodes.memory.WriteNode; import jdk.graal.compiler.nodes.memory.address.AddressNode; import jdk.graal.compiler.nodes.memory.address.OffsetAddressNode; import jdk.graal.compiler.nodes.spi.Replacements; @@ -190,7 +200,6 @@ import jdk.vm.ci.meta.SpeculationLog; import jdk.vm.ci.meta.SpeculationLog.SpeculationReason; import jdk.vm.ci.meta.UnresolvedJavaType; -import org.graalvm.nativeimage.ImageInfo; /** * Defines the {@link Plugins} used when running on HotSpot. @@ -663,14 +672,28 @@ private static boolean isAnnotatedByChangesCurrentThread(ResolvedJavaMethod meth return false; } + private static AddressNode getScopedValueCacheAddress(GraphBuilderContext b, HotSpotInvocationPluginHelper helper) { + CurrentJavaThreadNode javaThread = b.add(new CurrentJavaThreadNode(helper.getWordKind())); + ValueNode scopedValueCacheHandle = helper.readJavaThreadScopedValueCache(javaThread); + return b.add(OffsetAddressNode.create(scopedValueCacheHandle)); + } + private static void registerThreadPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) { + BarrierSet barrierSet = replacements.getProviders().getPlatformConfigurationProvider().getBarrierSet(); Registration r = new Registration(plugins, Thread.class, replacements); r.register(new InvocationPlugin("currentThread") { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { - ValueNode value = helper.readCurrentThreadObject(true); - b.push(JavaKind.Object, value); + CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(helper.getWordKind())); + ValueNode vthreadHandle = helper.readJavaThreadVthread(thread); + // Read the Object from the OopHandle + AddressNode handleAddress = b.add(OffsetAddressNode.create(vthreadHandle)); + // JavaThread::_vthread is never compressed + ObjectStamp threadStamp = StampFactory.objectNonNull(TypeReference.create(b.getAssumptions(), b.getMetaAccess().lookupJavaType(Thread.class))); + ValueNode read = new ReadNode(handleAddress, HOTSPOT_CURRENT_THREAD_OOP_HANDLE_LOCATION, threadStamp, + barrierSet.readBarrierType(HOTSPOT_CURRENT_THREAD_OOP_HANDLE_LOCATION, handleAddress, threadStamp), MemoryOrderMode.PLAIN); + b.addPush(JavaKind.Object, read); } return true; } @@ -680,8 +703,15 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { - ValueNode value = helper.readCurrentThreadObject(false); - b.push(JavaKind.Object, value); + CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(helper.getWordKind())); + ValueNode cthreadHandle = helper.readJavaThreadThreadObj(thread); + // Read the Object from the OopHandle + AddressNode handleAddress = b.add(OffsetAddressNode.create(cthreadHandle)); + // JavaThread::_threadObj is never compressed + ObjectStamp threadStamp = StampFactory.objectNonNull(TypeReference.create(b.getAssumptions(), b.getMetaAccess().lookupJavaType(Thread.class))); + ValueNode read = new ReadNode(handleAddress, HOTSPOT_CARRIER_THREAD_OOP_HANDLE_LOCATION, threadStamp, + barrierSet.readBarrierType(HOTSPOT_CARRIER_THREAD_OOP_HANDLE_LOCATION, handleAddress, threadStamp), MemoryOrderMode.PLAIN); + b.addPush(JavaKind.Object, read); } return true; } @@ -693,7 +723,22 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec GraalError.guarantee(ImageInfo.inImageRuntimeCode() || isAnnotatedByChangesCurrentThread(b.getMethod()), "method changes current Thread but is not annotated ChangesCurrentThread"); try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { receiver.get(true); - helper.setCurrentThread(thread); + CurrentJavaThreadNode javaThread = b.add(new CurrentJavaThreadNode(helper.getWordKind())); + ValueNode threadObjectHandle = helper.readJavaThreadVthread(javaThread); + AddressNode handleAddress = b.add(OffsetAddressNode.create(threadObjectHandle)); + b.add(new WriteNode(handleAddress, HOTSPOT_CURRENT_THREAD_OOP_HANDLE_LOCATION, thread, + barrierSet.writeBarrierType(HOTSPOT_CURRENT_THREAD_OOP_HANDLE_LOCATION), MemoryOrderMode.PLAIN)); + + if (JavaVersionUtil.JAVA_SPEC > 21) { + GraalError.guarantee(config.javaThreadLockIDOffset != -1, "JavaThread::_lock_id should have been exported"); + // Change the lock_id of the JavaThread + ValueNode tid = helper.loadField(thread, helper.getField(b.getMetaAccess().lookupJavaType(Thread.class), "tid")); + OffsetAddressNode address = b.add(new OffsetAddressNode(javaThread, helper.asWord(config.javaThreadLockIDOffset))); + b.add(new JavaWriteNode(JavaKind.Long, address, JAVA_THREAD_LOCK_ID_LOCATION, tid, BarrierType.NONE, false)); + } + if (HotSpotReplacementsUtil.supportsVirtualThreadUpdateJFR(config)) { + b.add(new VirtualThreadUpdateJFRNode(thread)); + } } return true; } @@ -703,7 +748,11 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { - b.push(JavaKind.Object, helper.readThreadScopedValueCache()); + AddressNode handleAddress = getScopedValueCacheAddress(b, helper); + ObjectStamp stamp = StampFactory.object(TypeReference.create(b.getAssumptions(), b.getMetaAccess().lookupJavaType(Object[].class))); + b.push(JavaKind.Object, b.add(new ReadNode(handleAddress, HOTSPOT_JAVA_THREAD_SCOPED_VALUE_CACHE_HANDLE_LOCATION, stamp, + barrierSet.readBarrierType(HOTSPOT_JAVA_THREAD_SCOPED_VALUE_CACHE_HANDLE_LOCATION, handleAddress, stamp), + MemoryOrderMode.PLAIN))); } return true; } @@ -713,7 +762,10 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode cache) { try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { - helper.setThreadScopedValueCache(cache); + AddressNode handleAddress = getScopedValueCacheAddress(b, helper); + b.add(new WriteNode(handleAddress, HOTSPOT_JAVA_THREAD_SCOPED_VALUE_CACHE_HANDLE_LOCATION, cache, + barrierSet.writeBarrierType(HOTSPOT_JAVA_THREAD_SCOPED_VALUE_CACHE_HANDLE_LOCATION), + MemoryOrderMode.PLAIN)); } return true; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotWordOperationPlugin.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotWordOperationPlugin.java index fb8085184a73..15b068375ee1 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotWordOperationPlugin.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotWordOperationPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -134,6 +134,11 @@ protected void processHotSpotWordOperation(GraphBuilderContext b, ResolvedJavaMe b.addPush(returnKind, PointerCastNode.create(StampFactory.forKind(wordKind), args[0])); break; + case FROM_COMPRESSED_POINTER: + assert args.length == 1 : args; + b.addPush(returnKind, PointerCastNode.create(StampFactory.forKind(JavaKind.Int), args[0])); + break; + case TO_KLASS_POINTER: assert args.length == 1 : args; b.addPush(returnKind, PointerCastNode.create(KlassPointerStamp.klass(), args[0])); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/DigestBaseSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/DigestBaseSnippets.java index 3eca041374a4..9374fe29d951 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/DigestBaseSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/DigestBaseSnippets.java @@ -98,7 +98,7 @@ static int implCompressMultiBlock0(Object receiver, byte[] buf, int ofs, int lim Object sha3obj = PiNode.piCast(realReceiver, sha3type, false, true, SnippetAnchorNode.anchor()); int blockSize = RawLoadNode.loadInt(sha3obj, HotSpotReplacementsUtil.getFieldOffset(sha3type, "blockSize"), JavaKind.Int, LocationIdentity.any()); Object state = RawLoadNode.load(sha3obj, HotSpotReplacementsUtil.getFieldOffset(sha3type, "state"), JavaKind.Object, LocationIdentity.any()); - Word stateAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(state, ReplacementsUtil.getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Int))); + Word stateAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(state, ReplacementsUtil.getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Long))); return HotSpotBackend.sha3ImplCompressMBStub(bufAddr, stateAddr, blockSize, ofs, limit); } else { return FallbackInvokeWithExceptionNode.fallbackFunctionCallInt(); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java index e935c89093fd..67a3c37d1eb6 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * 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,10 +27,11 @@ import static jdk.graal.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; import static jdk.graal.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.IDENTITY_HASHCODE; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.identityHashCode; -import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.identityHashCodeShift; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadWordFromObject; -import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.lockMaskInPlace; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.markOffset; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.markWordHashCodeShift; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.markWordHashMark; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.markWordLockMaskInPlace; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.monitorValue; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.uninitializedIdentityHashCodeValue; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.unlockedValue; @@ -57,26 +58,31 @@ protected int computeIdentityHashCode(final Object x) { // In HotSpot, the upper bits (i.e., [63:2] in 64-bits VM) of the mark word in object header // are - // 1) not used with lightweight locking; + // 1) not used or partially used (i.e., [63:42] in 64-bits VM to store compressed class + // pointer with -XX:+UseCompactObjectHeaders) with lightweight locking; // 2) pointer to the displaced mark in a thread's stack with stack locking; or - // 3) pointer to the monitor object with heavy monitor locking. + // 3) pointer to the monitor object with heavy monitor locking when + // -XX:+UseObjectMonitorTable is not specified. // - // When these upper bits are not used, i.e., when an object is either unlocked or locked - // with lightweight locking, HotSpot reuses fraction of the upper bits (e.g., [38:8] in - // 64-bits VM) for caching the identity hash code. Therefore, + // When an object is either unlocked, locked with lightweight locking, locked with heavy + // monitor locking using -XX:+UseObjectMonitorTable, HotSpot reuses fraction of the upper + // bits (e.g., [41:11] in 64-bits VM) for caching the identity hash code. + // Therefore, // 1) when lightweight locking is employed as fast locking scheme (-XX:LockingMode=2), we - // only need to test if the object is NOT in a monitor-locked state, i.e., lock bits not - // equals to 0b10; + // only need to test if UseObjectMonitorTable is specified or if the object is NOT in a + // monitor-locked state, i.e., lock bits not equals to 0b10; // 2) when stack locking is employed as fast locking scheme (-XX:LockingMode=1) or no fast // locking scheme is employed (-XX:LockingMode=0), we need to test if the object is // unlocked, i.e., lock bits equals to 0b01. // // See src/hotspot/share/oops/markWord.hpp for more details. - final Word lockBits = mark.and(lockMaskInPlace(INJECTED_VMCONFIG)); - if (probability(FAST_PATH_PROBABILITY, useObjectMonitorTable(INJECTED_VMCONFIG) || + final Word lockBits = mark.and(WordFactory.unsigned(markWordLockMaskInPlace(INJECTED_VMCONFIG))); + if (useObjectMonitorTable(INJECTED_VMCONFIG) || probability(FAST_PATH_PROBABILITY, useLightweightLocking(INJECTED_VMCONFIG) ? lockBits.notEqual(WordFactory.unsigned(monitorValue(INJECTED_VMCONFIG))) : lockBits.equal(WordFactory.unsigned(unlockedValue(INJECTED_VMCONFIG))))) { - int hash = (int) mark.unsignedShiftRight(identityHashCodeShift(INJECTED_VMCONFIG)).rawValue(); + // `& markWord::hash_mask' is essential with -XX:+UseCompactObjectHeaders, because bit + // 42 might be set. + int hash = (int) mark.unsignedShiftRight(markWordHashCodeShift(INJECTED_VMCONFIG)).and((int) markWordHashMark(INJECTED_VMCONFIG)).rawValue(); if (probability(FAST_PATH_PROBABILITY, hash != uninitializedIdentityHashCodeValue(INJECTED_VMCONFIG))) { return hash; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotInvocationPluginHelper.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotInvocationPluginHelper.java index 557f380fc071..d3c964bc6e88 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotInvocationPluginHelper.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotInvocationPluginHelper.java @@ -26,9 +26,6 @@ import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.ARRAY_KLASS_COMPONENT_MIRROR; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_ARRAY_KLASS_LOCATION; -import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.HOTSPOT_CARRIER_THREAD_OOP_HANDLE_LOCATION; -import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.HOTSPOT_CURRENT_THREAD_OOP_HANDLE_LOCATION; -import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.HOTSPOT_JAVA_THREAD_SCOPED_VALUE_CACHE_HANDLE_LOCATION; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.HOTSPOT_OOP_HANDLE_LOCATION; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_CARRIER_THREAD_OBJECT_LOCATION; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_CURRENT_THREAD_OBJECT_LOCATION; @@ -41,17 +38,15 @@ import java.util.function.Function; -import jdk.graal.compiler.core.common.type.AbstractPointerStamp; import org.graalvm.word.LocationIdentity; import jdk.graal.compiler.core.common.memory.MemoryOrderMode; -import jdk.graal.compiler.core.common.type.ObjectStamp; +import jdk.graal.compiler.core.common.type.AbstractPointerStamp; import jdk.graal.compiler.core.common.type.Stamp; import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.core.common.type.TypeReference; import jdk.graal.compiler.hotspot.GraalHotSpotVMConfig; import jdk.graal.compiler.hotspot.nodes.CurrentJavaThreadNode; -import jdk.graal.compiler.hotspot.nodes.VirtualThreadUpdateJFRNode; import jdk.graal.compiler.hotspot.nodes.type.KlassPointerStamp; import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.PiNode; @@ -61,9 +56,7 @@ import jdk.graal.compiler.nodes.gc.BarrierSet; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.memory.ReadNode; -import jdk.graal.compiler.nodes.memory.WriteNode; import jdk.graal.compiler.nodes.memory.address.AddressNode; -import jdk.graal.compiler.nodes.memory.address.OffsetAddressNode; import jdk.graal.compiler.nodes.type.StampTool; import jdk.graal.compiler.replacements.InvocationPluginHelper; import jdk.vm.ci.meta.JavaKind; @@ -225,60 +218,24 @@ public ValueNode loadArrayKlass(ValueNode componentType) { } /** - * Reads thread object from current thread. {@code readVirtualThread} indicates whether the - * caller wants the current virtual thread or its carrier -- the current platform thread. + * Read {@code JavaThread::_threadObj}. */ - public ValueNode readCurrentThreadObject(boolean readVirtualThread) { - CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(getWordKind())); - // JavaThread::_vthread and JavaThread::_threadObj are never compressed - ObjectStamp threadStamp = StampFactory.objectNonNull(TypeReference.create(b.getAssumptions(), b.getMetaAccess().lookupJavaType(Thread.class))); - Stamp fieldStamp = StampFactory.forKind(getWordKind()); - ValueNode value = readLocation(thread, readVirtualThread ? HotSpotVMConfigField.JAVA_THREAD_THREAD_OBJECT : HotSpotVMConfigField.JAVA_THREAD_CARRIER_THREAD_OBJECT, fieldStamp); - - // Read the Object from the OopHandle - AddressNode handleAddress = b.add(OffsetAddressNode.create(value)); - LocationIdentity location = readVirtualThread ? HOTSPOT_CURRENT_THREAD_OOP_HANDLE_LOCATION : HOTSPOT_CARRIER_THREAD_OOP_HANDLE_LOCATION; - value = b.add(new ReadNode(handleAddress, location, threadStamp, barrierSet.readBarrierType(location, handleAddress, threadStamp), MemoryOrderMode.PLAIN)); - return value; - } - - /** - * Sets {@code thread} into {@code JavaThread::_vthread}. - */ - public void setCurrentThread(ValueNode thread) { - CurrentJavaThreadNode javaThread = b.add(new CurrentJavaThreadNode(getWordKind())); - ValueNode threadObjectHandle = readLocation(javaThread, HotSpotVMConfigField.JAVA_THREAD_THREAD_OBJECT, StampFactory.forKind(getWordKind())); - AddressNode handleAddress = b.add(OffsetAddressNode.create(threadObjectHandle)); - b.add(new WriteNode(handleAddress, HOTSPOT_CURRENT_THREAD_OOP_HANDLE_LOCATION, thread, barrierSet.writeBarrierType(HOTSPOT_CURRENT_THREAD_OOP_HANDLE_LOCATION), MemoryOrderMode.PLAIN)); - if (HotSpotReplacementsUtil.supportsVirtualThreadUpdateJFR(config)) { - b.add(new VirtualThreadUpdateJFRNode(thread)); - } - } - - private AddressNode scopedValueCacheHelper() { - CurrentJavaThreadNode javaThread = b.add(new CurrentJavaThreadNode(getWordKind())); - ValueNode scopedValueCacheHandle = readLocation(javaThread, HotSpotVMConfigField.JAVA_THREAD_SCOPED_VALUE_CACHE_OFFSET, StampFactory.forKind(getWordKind())); - return b.add(OffsetAddressNode.create(scopedValueCacheHandle)); + public ValueNode readJavaThreadThreadObj(CurrentJavaThreadNode javaThread) { + return readLocation(javaThread, HotSpotVMConfigField.JAVA_THREAD_CARRIER_THREAD_OBJECT, StampFactory.forKind(getWordKind())); } /** - * Reads {@code JavaThread::_scopedValueCache}. + * Read {@code JavaThread::_vthread}. */ - public ValueNode readThreadScopedValueCache() { - AddressNode handleAddress = scopedValueCacheHelper(); - ObjectStamp stamp = StampFactory.object(TypeReference.create(b.getAssumptions(), b.getMetaAccess().lookupJavaType(Object[].class))); - return b.add(new ReadNode(handleAddress, HOTSPOT_JAVA_THREAD_SCOPED_VALUE_CACHE_HANDLE_LOCATION, stamp, - barrierSet.readBarrierType(HOTSPOT_JAVA_THREAD_SCOPED_VALUE_CACHE_HANDLE_LOCATION, handleAddress, stamp), MemoryOrderMode.PLAIN)); + public ValueNode readJavaThreadVthread(CurrentJavaThreadNode javaThread) { + return readLocation(javaThread, HotSpotVMConfigField.JAVA_THREAD_THREAD_OBJECT, StampFactory.forKind(getWordKind())); } /** - * Sets {@code cache} into {@code JavaThread::_scopedValueCache}. + * Read {@code JavaThread::_scopedValueCache}. */ - public void setThreadScopedValueCache(ValueNode cache) { - AddressNode handleAddress = scopedValueCacheHelper(); - b.add(new WriteNode(handleAddress, HOTSPOT_JAVA_THREAD_SCOPED_VALUE_CACHE_HANDLE_LOCATION, cache, - barrierSet.writeBarrierType(HOTSPOT_JAVA_THREAD_SCOPED_VALUE_CACHE_HANDLE_LOCATION), - MemoryOrderMode.PLAIN)); + public ValueNode readJavaThreadScopedValueCache(CurrentJavaThreadNode javaThread) { + return readLocation(javaThread, HotSpotVMConfigField.JAVA_THREAD_SCOPED_VALUE_CACHE_OFFSET, StampFactory.forKind(getWordKind())); } /** diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotReplacementsUtil.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotReplacementsUtil.java index a33037501696..d0a434c52a16 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotReplacementsUtil.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotReplacementsUtil.java @@ -27,15 +27,19 @@ import static jdk.graal.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; import static jdk.graal.compiler.hotspot.GraalHotSpotVMConfigAccess.JDK; import static jdk.graal.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.VERIFY_OOP; +import static jdk.graal.compiler.nodes.CompressionNode.CompressionOp.Compress; import java.lang.ref.Reference; import org.graalvm.word.LocationIdentity; +import org.graalvm.word.WordFactory; import jdk.graal.compiler.api.replacements.Fold; import jdk.graal.compiler.api.replacements.Fold.InjectedParameter; +import jdk.graal.compiler.core.common.CompressEncoding; import jdk.graal.compiler.core.common.SuppressFBWarnings; import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; +import jdk.graal.compiler.core.common.type.IntegerStamp; import jdk.graal.compiler.core.common.type.ObjectStamp; import jdk.graal.compiler.core.common.type.Stamp; import jdk.graal.compiler.core.common.type.TypeReference; @@ -44,13 +48,20 @@ import jdk.graal.compiler.graph.Node.NodeIntrinsic; import jdk.graal.compiler.hotspot.GraalHotSpotVMConfig; import jdk.graal.compiler.hotspot.meta.HotSpotLoweringProvider; +import jdk.graal.compiler.hotspot.meta.HotSpotProviders; +import jdk.graal.compiler.hotspot.nodes.HotSpotCompressionNode; +import jdk.graal.compiler.hotspot.nodes.type.KlassPointerStamp; import jdk.graal.compiler.hotspot.word.KlassPointer; +import jdk.graal.compiler.hotspot.word.PointerCastNode; import jdk.graal.compiler.nodes.CanonicalizableLocation; import jdk.graal.compiler.nodes.CompressionNode; +import jdk.graal.compiler.nodes.CompressionNode.CompressionOp; import jdk.graal.compiler.nodes.ConstantNode; import jdk.graal.compiler.nodes.NamedLocationIdentity; import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.calc.LeftShiftNode; +import jdk.graal.compiler.nodes.calc.ZeroExtendNode; import jdk.graal.compiler.nodes.extended.ForeignCallNode; import jdk.graal.compiler.nodes.extended.LoadHubNode; import jdk.graal.compiler.nodes.extended.LoadHubOrNullNode; @@ -64,6 +75,7 @@ import jdk.graal.compiler.replacements.ReplacementsUtil; import jdk.graal.compiler.replacements.nodes.ReadRegisterNode; import jdk.graal.compiler.word.Word; +import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.code.Register; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; @@ -315,6 +327,8 @@ public static Object getPendingException(Word thread) { public static final LocationIdentity JAVA_THREAD_CARRIER_THREAD_OBJECT_LOCATION = NamedLocationIdentity.mutable("JavaThread::_threadObj"); + public static final LocationIdentity JAVA_THREAD_LOCK_ID_LOCATION = NamedLocationIdentity.mutable("JavaThread::_lock_id"); + public static final LocationIdentity JAVA_THREAD_OSTHREAD_LOCATION = NamedLocationIdentity.mutable("JavaThread::_osthread"); public static final LocationIdentity JAVA_THREAD_HOLD_MONITOR_COUNT_LOCATION = NamedLocationIdentity.mutable("JavaThread::_held_monitor_count"); @@ -469,14 +483,56 @@ public ValueNode canonicalizeRead(ValueNode read, ValueNode object, ValueNode lo } }; + public static final LocationIdentity COMPACT_HUB_LOCATION = new HotSpotOptimizingLocationIdentity("CompactHub") { + @Override + public ValueNode canonicalizeRead(ValueNode read, ValueNode object, ValueNode location, NodeView view, CoreProviders tool) { + TypeReference constantType = StampTool.typeReferenceOrNull(object); + if (constantType != null && constantType.isExact()) { + GraalHotSpotVMConfig config = ((HotSpotProviders) tool.getReplacements().getProviders()).getConfig(); + KlassPointerStamp hubStamp = KlassPointerStamp.klassNonNull().compressed(config.getKlassEncoding()); + ConstantNode compressedHub = ConstantNode.forConstant(hubStamp, ((HotSpotMetaspaceConstant) tool.getConstantReflection().asObjectHub(constantType.getType())).compress(), + tool.getMetaAccess()); + ValueNode rawCompressedHub = PointerCastNode.create(IntegerStamp.create(32, 0, CodeUtil.mask(64 - config.markWordKlassShift)), compressedHub); + ValueNode rawCompressedHubWordSize = ZeroExtendNode.create(rawCompressedHub, 32, 64, NodeView.DEFAULT); + return LeftShiftNode.create(rawCompressedHubWordSize, ConstantNode.forInt(config.markWordKlassShift), NodeView.DEFAULT); + } + return read; + } + }; + + @Fold + public static boolean useCompactObjectHeaders(@InjectedParameter GraalHotSpotVMConfig config) { + return config.useCompactObjectHeaders; + } + + @Fold + public static int markWordKlassShift(@InjectedParameter GraalHotSpotVMConfig config) { + return config.markWordKlassShift; + } + + @NodeIntrinsic(HotSpotCompressionNode.class) + private static native KlassPointer compress(@ConstantNodeParameter CompressionOp op, KlassPointer hub, @ConstantNodeParameter CompressEncoding encoding); + @Fold static int hubOffset(@InjectedParameter GraalHotSpotVMConfig config) { return config.hubOffset; } + @Fold + static CompressEncoding klassEncoding(@InjectedParameter GraalHotSpotVMConfig config) { + return config.getKlassEncoding(); + } + public static void initializeObjectHeader(Word memory, Word markWord, KlassPointer hub) { - memory.writeWord(markOffset(INJECTED_VMCONFIG), markWord, MARK_WORD_LOCATION); - StoreHubNode.write(memory, hub); + if (useCompactObjectHeaders(INJECTED_VMCONFIG)) { + Word compressedHub = WordFactory.unsigned(compress(Compress, hub, klassEncoding(INJECTED_VMCONFIG)).asInt()); + Word hubInPlace = compressedHub.shiftLeft(markWordKlassShift(INJECTED_VMCONFIG)); + Word newMarkWord = markWord.or(hubInPlace); + memory.writeWord(markOffset(INJECTED_VMCONFIG), newMarkWord, MARK_WORD_LOCATION); + } else { + memory.writeWord(markOffset(INJECTED_VMCONFIG), markWord, MARK_WORD_LOCATION); + StoreHubNode.write(memory, hub); + } } @Fold @@ -504,6 +560,11 @@ public static int monitorValue(@InjectedParameter GraalHotSpotVMConfig config) { return config.monitorValue; } + @Fold + public static int unusedMark(@InjectedParameter GraalHotSpotVMConfig config) { + return config.unusedMark; + } + @Fold public static int objectMonitorOwnerOffset(@InjectedParameter GraalHotSpotVMConfig config) { return config.objectMonitorOwner; @@ -535,8 +596,8 @@ public static int objectMonitorSuccOffset(@InjectedParameter GraalHotSpotVMConfi * bits afterwards due to elimination of the biased locking. */ @Fold - public static int lockMaskInPlace(@InjectedParameter GraalHotSpotVMConfig config) { - return config.lockMaskInPlace; + public static long markWordLockMaskInPlace(@InjectedParameter GraalHotSpotVMConfig config) { + return config.markWordLockMaskInPlace; } @Fold @@ -569,6 +630,9 @@ public static int objectAlignment(@InjectedParameter GraalHotSpotVMConfig config @Fold public static int instanceHeaderSize(@InjectedParameter GraalHotSpotVMConfig config) { + if (config.useCompactObjectHeaders) { + return wordSize(); + } return config.useCompressedClassPointers ? (2 * wordSize()) - 4 : 2 * wordSize(); } @@ -679,6 +743,8 @@ public static int secondarySupersOffset(@InjectedParameter GraalHotSpotVMConfig public static final LocationIdentity OBJECT_MONITOR_SUCC_LOCATION = NamedLocationIdentity.mutable("ObjectMonitor::_succ"); + public static final LocationIdentity OBJECT_MONITOR_STACK_LOCKER_LOCATION = NamedLocationIdentity.mutable("ObjectMonitor::_stack_locker"); + @Fold public static int lockMetadataOffset(@InjectedParameter GraalHotSpotVMConfig config) { return config.basicLockMetadataOffset; @@ -689,6 +755,11 @@ static int heldMonitorCountOffset(@InjectedParameter GraalHotSpotVMConfig config return config.threadHeldMonitorCountOffset; } + @Fold + static int javaThreadLockIDOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.javaThreadLockIDOffset; + } + @Fold static int javaThreadLockStackTopOffset(@InjectedParameter GraalHotSpotVMConfig config) { return config.threadLockStackOffset + config.lockStackTopOffset; @@ -736,7 +807,7 @@ public static int jvmAccIsValueBasedClass(@InjectedParameter GraalHotSpotVMConfi @Fold public static long defaultPrototypeMarkWord(@InjectedParameter GraalHotSpotVMConfig config) { - return config.defaultPrototypeMarkWord(); + return config.markWordNoHashInPlace | config.markWordNoLockInPlace; } @Fold @@ -745,8 +816,13 @@ static int uninitializedIdentityHashCodeValue(@InjectedParameter GraalHotSpotVMC } @Fold - static int identityHashCodeShift(@InjectedParameter GraalHotSpotVMConfig config) { - return config.identityHashCodeShift; + static int markWordHashCodeShift(@InjectedParameter GraalHotSpotVMConfig config) { + return config.markWordHashCodeShift; + } + + @Fold + static long markWordHashMark(@InjectedParameter GraalHotSpotVMConfig config) { + return config.markWordHashMask; } /** @@ -787,17 +863,17 @@ public static long verifyOopCounterAddress(@InjectedParameter GraalHotSpotVMConf private static native Object verifyOopStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object); public static Word loadWordFromObject(Object object, int offset) { - ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject"); + ReplacementsUtil.staticAssert(useCompactObjectHeaders(INJECTED_VMCONFIG) || offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject"); return loadWordFromObjectIntrinsic(object, offset, LocationIdentity.any(), getWordKind()); } public static Word loadWordFromObject(Object object, int offset, LocationIdentity identity) { - ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject"); + ReplacementsUtil.staticAssert(useCompactObjectHeaders(INJECTED_VMCONFIG) || offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject"); return loadWordFromObjectIntrinsic(object, offset, identity, getWordKind()); } public static KlassPointer loadKlassFromObject(Object object, int offset, LocationIdentity identity) { - ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadKlassFromObject"); + ReplacementsUtil.staticAssert(useCompactObjectHeaders(INJECTED_VMCONFIG) || offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadKlassFromObject"); return loadKlassFromObjectIntrinsic(object, offset, identity, getWordKind()); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/MonitorSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/MonitorSnippets.java index 59970602b3aa..2cbc75590343 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/MonitorSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/MonitorSnippets.java @@ -34,6 +34,7 @@ import static jdk.graal.compiler.hotspot.nodes.VMErrorNode.vmError; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.BASICLOCK_METADATA_LOCATION; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_HOLD_MONITOR_COUNT_LOCATION; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_LOCK_ID_LOCATION; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_LOCK_STACK_LOCATION; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_LOCK_STACK_TOP_LOCATION; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_OM_CACHE_LOCATION; @@ -45,9 +46,12 @@ import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_ENTRY_LIST_LOCATION; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_OWNER_LOCATION; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_RECURSION_LOCATION; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_STACK_LOCKER_LOCATION; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_SUCC_LOCATION; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.diagnoseSyncOnValueBasedClasses; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.heldMonitorCountOffset; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.isCAssertEnabled; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.javaThreadLockIDOffset; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.javaThreadLockStackEndOffset; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.javaThreadLockStackTopOffset; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.javaThreadOomCacheOffset; @@ -56,9 +60,9 @@ import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassAccessFlagsOffset; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassMiscFlagsOffset; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadWordFromObject; -import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.lockMaskInPlace; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.lockMetadataOffset; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.markOffset; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.markWordLockMaskInPlace; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.monitorValue; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.objectMonitorCxqOffset; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.objectMonitorEntryListOffset; @@ -71,6 +75,7 @@ import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.shouldUseKlassMiscFlags; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.unlockedValue; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.unusedMark; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.useLightweightLocking; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.useObjectMonitorTable; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.useStackLocking; @@ -89,6 +94,7 @@ import static jdk.graal.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; import static jdk.graal.compiler.replacements.nodes.CStringConstant.cstring; import static org.graalvm.word.LocationIdentity.any; +import static org.graalvm.word.WordFactory.nullPointer; import static org.graalvm.word.WordFactory.unsigned; import static org.graalvm.word.WordFactory.zero; @@ -162,7 +168,11 @@ * * 64 bits: * -------- - * unused:25 hash:31 -->| unused_gap:1 age:4 unused_gap:1 lock:2 (normal object) + * unused:22 hash:31 -->| unused_gap:4 age:4 self-fwd:1 lock:2 (normal object) + * + * 64 bits (with compact headers): + * -------- + * nklass:22 hash:31 -->| unused_gap:4 age:4 self-fwd:1 lock:2 (normal object) * * - hash contains the identity hash value: largest value is * 31 bits, see os::random(). Also, 64-bit vm's require @@ -175,6 +185,7 @@ * [header | 00] locked locked regular object header (fast-locking in use) * [header | 01] unlocked regular object header * [ptr | 10] monitor inflated lock (header is swapped out) + * [header | 10] monitor inflated lock (UseObjectMonitorTable == true) * [ptr | 11] marked used to mark an object * [0 ............ 0| 00] inflating inflation in progress (stack-locking in use) * @@ -194,6 +205,16 @@ // @formatter:on public class MonitorSnippets implements Snippets { + /** + * This helper method is for bypassing the mandatory branch probabilities for snippets. + * + * See also {@code jdk.graal.compiler.core.test.VerifySnippetProbabilities} + */ + @Fold + public static boolean isJDK21() { + return JavaVersionUtil.JAVA_SPEC == 21; + } + /** * The monitorenter snippet is slightly different from the HotSpot code: * @@ -229,7 +250,9 @@ public static void monitorenter(Object object, KlassPointer hub, @ConstantParame } if (tryFastPathLocking(object, stackPointerRegister, trace, counters, mark, lock, thread)) { - incrementHeldMonitorCount(thread); + if (isJDK21() || useStackLocking(INJECTED_VMCONFIG)) { + incrementHeldMonitorCount(thread); + } } else { // slow-path runtime-call monitorenterStubC(MONITORENTER, object, lock); @@ -289,22 +312,27 @@ private static boolean tryEnterInflated(Object object, Word lock, Word mark, Wor cacheIter = cacheIter.add(stepSize); } } + + // Cache the monitor for unlock before trashing box. On failure to acquire + // the lock, the slow path will reset the entry accordingly (see CacheSetter). + writeMonitorCache(lock, monitor); } else { // mark is a pointer to the ObjectMonitor + monitorMask - monitor = mark.subtract(HotSpotReplacementsUtil.monitorValue(INJECTED_VMCONFIG)); + monitor = mark.subtract(monitorValue(INJECTED_VMCONFIG)); } - int ownerOffset = HotSpotReplacementsUtil.objectMonitorOwnerOffset(INJECTED_VMCONFIG); - Word owner = monitor.readWord(ownerOffset, HotSpotReplacementsUtil.OBJECT_MONITOR_OWNER_LOCATION); + int ownerOffset = objectMonitorOwnerOffset(INJECTED_VMCONFIG); + Word owner = monitor.readWord(ownerOffset, OBJECT_MONITOR_OWNER_LOCATION); + Word newOwner = isJDK21() ? thread : thread.readWord(javaThreadLockIDOffset(INJECTED_VMCONFIG), JAVA_THREAD_LOCK_ID_LOCATION); + // The following owner null check is essential. In the case where the null check fails, it // avoids the subsequent bound-to-fail CAS operation, which would have caused the // invalidation of the L1 cache of the core that runs the lock owner thread, and thus causes // the lock to be held slightly longer. - if (probability(FREQUENT_PROBABILITY, owner.equal(0))) { - // it appears unlocked (owner == 0) - if (probability(FREQUENT_PROBABILITY, monitor.logicCompareAndSwapWord(ownerOffset, owner, thread, HotSpotReplacementsUtil.OBJECT_MONITOR_OWNER_LOCATION))) { + if (probability(FREQUENT_PROBABILITY, owner.equal(nullPointer()))) { + // it appears unlocked (owner == null) + if (probability(FREQUENT_PROBABILITY, monitor.logicCompareAndSwapWord(ownerOffset, owner, newOwner, OBJECT_MONITOR_OWNER_LOCATION))) { // success - writeMonitorCache(lock, monitor); traceObject(trace, "+lock{heavyweight:cas}", object, true); counters.lockHeavyCas.inc(); return true; @@ -312,11 +340,10 @@ private static boolean tryEnterInflated(Object object, Word lock, Word mark, Wor traceObject(trace, "+lock{heavyweight:failed-cas}", object, true); counters.lockHeavyFailedCas.inc(); } - } else if (probability(NOT_LIKELY_PROBABILITY, owner.equal(thread))) { - int recursionsOffset = HotSpotReplacementsUtil.objectMonitorRecursionsOffset(INJECTED_VMCONFIG); - Word recursions = monitor.readWord(recursionsOffset, HotSpotReplacementsUtil.OBJECT_MONITOR_RECURSION_LOCATION); - monitor.writeWord(recursionsOffset, recursions.add(1), HotSpotReplacementsUtil.OBJECT_MONITOR_RECURSION_LOCATION); - writeMonitorCache(lock, monitor); + } else if (probability(NOT_LIKELY_PROBABILITY, owner.equal(newOwner))) { + int recursionsOffset = objectMonitorRecursionsOffset(INJECTED_VMCONFIG); + Word recursions = monitor.readWord(recursionsOffset, OBJECT_MONITOR_RECURSION_LOCATION); + monitor.writeWord(recursionsOffset, recursions.add(1), OBJECT_MONITOR_RECURSION_LOCATION); traceObject(trace, "+lock{heavyweight:recursive}", object, true); counters.lockHeavyRecursive.inc(); return true; @@ -331,7 +358,7 @@ private static boolean tryStackLocking(Object object, Word lock, Word mark, Word if (probability(SLOW_PATH_PROBABILITY, mark.and(monitorValue(INJECTED_VMCONFIG)).notEqual(0))) { // Inflated case // Set the lock slot's displaced mark to unused. Any non-0 value suffices. - lock.writeWord(lockMetadataOffset(INJECTED_VMCONFIG), WordFactory.unsigned(3), BASICLOCK_METADATA_LOCATION); + lock.writeWord(lockMetadataOffset(INJECTED_VMCONFIG), WordFactory.unsigned(unusedMark(INJECTED_VMCONFIG)), BASICLOCK_METADATA_LOCATION); return tryEnterInflated(object, lock, mark, thread, trace, counters); } @@ -463,7 +490,9 @@ public static void monitorexit(Object object, @ConstantParameter int lockDepth, trace(trace, " lock: 0x%016lx\n", lock); if (tryFastPathUnlocking(object, trace, counters, thread, lock)) { - decrementHeldMonitorCount(thread); + if (isJDK21() || useStackLocking(INJECTED_VMCONFIG)) { + decrementHeldMonitorCount(thread); + } } else { monitorexitStubC(MONITOREXIT, object, lock); } @@ -498,7 +527,7 @@ private static boolean tryStackUnlocking(Object object, Word thread, Word lock, Word mark = loadWordFromObject(object, markOffset(INJECTED_VMCONFIG)); if (probability(SLOW_PATH_PROBABILITY, mark.and(monitorValue(INJECTED_VMCONFIG)).notEqual(0))) { - return tryExitInflated(object, thread, lock, trace, counters); + return tryExitInflated(object, mark, thread, lock, trace, counters); } if (probability(VERY_FAST_PATH_PROBABILITY, Word.objectToTrackedPointer(object).logicCompareAndSwapWord(markOffset(INJECTED_VMCONFIG), @@ -538,7 +567,7 @@ private static boolean tryLightweightUnlocking(Object object, Word thread, Word AssertionSnippets.vmMessageC(VM_MESSAGE_C, true, cstring("Fast Unlock not monitor"), 0L, 0L, 0L); } } - return tryExitInflated(object, thread, lock, trace, counters); + return tryExitInflated(object, mark, thread, lock, trace, counters); } // Pop lock-stack. @@ -557,7 +586,7 @@ private static boolean tryLightweightUnlocking(Object object, Word thread, Word // We elide the monitor check, let the CAS fail instead. // Try to unlock. Transition lock bits 0b00 => 0b01 - Word markLocked = mark.and(~lockMaskInPlace(INJECTED_VMCONFIG)); + Word markLocked = mark.and(WordFactory.unsigned(~markWordLockMaskInPlace(INJECTED_VMCONFIG))); Word markUnlocked = mark.or(unlockedValue(INJECTED_VMCONFIG)); if (probability(FAST_PATH_PROBABILITY, objectPointer.logicCompareAndSwapWord(markOffset(INJECTED_VMCONFIG), markLocked, markUnlocked, MARK_WORD_LOCATION))) { traceObject(trace, "-lock{lightweight:cas}", object, false); @@ -575,10 +604,8 @@ private static boolean tryLightweightUnlocking(Object object, Word thread, Word return false; } - private static boolean tryExitInflated(Object object, Word thread, Word lock, boolean trace, Counters counters) { + private static boolean tryExitInflated(Object object, Word mark, Word thread, Word lock, boolean trace, Counters counters) { // Inflated case - // mark is a pointer to the ObjectMonitor + monitorMask - Word mark = loadWordFromObject(object, markOffset(INJECTED_VMCONFIG)); Word monitor; if (useObjectMonitorTable(INJECTED_VMCONFIG)) { monitor = lock.readWord(lockMetadataOffset(INJECTED_VMCONFIG), BASICLOCK_METADATA_LOCATION); @@ -588,14 +615,16 @@ private static boolean tryExitInflated(Object object, Word thread, Word lock, bo return false; } } else { + // mark is a pointer to the ObjectMonitor + monitorMask monitor = mark.subtract(monitorValue(INJECTED_VMCONFIG)); } int ownerOffset = objectMonitorOwnerOffset(INJECTED_VMCONFIG); + int recursionsOffset = objectMonitorRecursionsOffset(INJECTED_VMCONFIG); Word recursions = monitor.readWord(recursionsOffset, OBJECT_MONITOR_RECURSION_LOCATION); if (probability(FAST_PATH_PROBABILITY, recursions.equal(0))) { - if (JavaVersionUtil.JAVA_SPEC == 21) { + if (isJDK21()) { // recursions == 0 Word entryList = monitor.readWord(objectMonitorEntryListOffset(INJECTED_VMCONFIG), OBJECT_MONITOR_ENTRY_LIST_LOCATION); Word cxq = monitor.readWord(objectMonitorCxqOffset(INJECTED_VMCONFIG), OBJECT_MONITOR_CXQ_LOCATION); @@ -604,7 +633,7 @@ private static boolean tryExitInflated(Object object, Word thread, Word lock, bo // Nobody is waiting, success // release_store memoryBarrier(MembarNode.FenceKind.STORE_RELEASE); - monitor.writeWord(ownerOffset, zero()); + monitor.writeWord(ownerOffset, nullPointer(), OBJECT_MONITOR_OWNER_LOCATION); traceObject(trace, "-lock{heavyweight:simple}", object, false); counters.unlockHeavySimple.inc(); return true; @@ -614,7 +643,7 @@ private static boolean tryExitInflated(Object object, Word thread, Word lock, bo if (probability(FREQUENT_PROBABILITY, succ.isNonNull())) { // There may be a thread spinning on this monitor. Temporarily setting // the monitor owner to null, and hope that the other thread will grab it. - monitor.writeWordVolatile(ownerOffset, zero()); + monitor.writeWordVolatile(ownerOffset, nullPointer()); succ = monitor.readWordVolatile(succOffset, OBJECT_MONITOR_SUCC_LOCATION); if (probability(NOT_FREQUENT_PROBABILITY, succ.isNonNull())) { // We manage to release the monitor before the other running thread even @@ -687,8 +716,8 @@ private static void decrementHeldMonitorCount(Word thread) { } private static void updateHeldMonitorCount(Word thread, int increment) { - Word heldMonitorCount = thread.readWord(HotSpotReplacementsUtil.heldMonitorCountOffset(INJECTED_VMCONFIG), HotSpotReplacementsUtil.JAVA_THREAD_HOLD_MONITOR_COUNT_LOCATION); - thread.writeWord(HotSpotReplacementsUtil.heldMonitorCountOffset(INJECTED_VMCONFIG), heldMonitorCount.add(increment), HotSpotReplacementsUtil.JAVA_THREAD_HOLD_MONITOR_COUNT_LOCATION); + Word heldMonitorCount = thread.readWord(heldMonitorCountOffset(INJECTED_VMCONFIG), JAVA_THREAD_HOLD_MONITOR_COUNT_LOCATION); + thread.writeWord(heldMonitorCountOffset(INJECTED_VMCONFIG), heldMonitorCount.add(increment), JAVA_THREAD_HOLD_MONITOR_COUNT_LOCATION); } @Fold @@ -816,7 +845,8 @@ public Templates(OptionValues options, SnippetCounter.Group.Factory factory, Hot JAVA_THREAD_LOCK_STACK_LOCATION, JAVA_THREAD_LOCK_STACK_TOP_LOCATION, JAVA_THREAD_OM_CACHE_LOCATION, - JAVA_THREAD_HOLD_MONITOR_COUNT_LOCATION}; + JAVA_THREAD_HOLD_MONITOR_COUNT_LOCATION, + JAVA_THREAD_LOCK_ID_LOCATION}; exitLocations = new LocationIdentity[]{ JAVA_THREAD_LOCK_STACK_LOCATION, JAVA_THREAD_LOCK_STACK_TOP_LOCATION, @@ -826,10 +856,13 @@ public Templates(OptionValues options, SnippetCounter.Group.Factory factory, Hot OBJECT_MONITOR_ENTRY_LIST_LOCATION, OBJECT_MONITOR_RECURSION_LOCATION, OBJECT_MONITOR_SUCC_LOCATION, + OBJECT_MONITOR_STACK_LOCKER_LOCATION, MARK_WORD_LOCATION, JAVA_THREAD_HOLD_MONITOR_COUNT_LOCATION}; } else { - enterLocations = new LocationIdentity[]{JAVA_THREAD_HOLD_MONITOR_COUNT_LOCATION}; + enterLocations = new LocationIdentity[]{ + JAVA_THREAD_HOLD_MONITOR_COUNT_LOCATION, + JAVA_THREAD_LOCK_ID_LOCATION}; exitLocations = new LocationIdentity[]{ BASICLOCK_METADATA_LOCATION, OBJECT_MONITOR_OWNER_LOCATION, @@ -837,6 +870,7 @@ public Templates(OptionValues options, SnippetCounter.Group.Factory factory, Hot OBJECT_MONITOR_ENTRY_LIST_LOCATION, OBJECT_MONITOR_RECURSION_LOCATION, OBJECT_MONITOR_SUCC_LOCATION, + OBJECT_MONITOR_STACK_LOCKER_LOCATION, MARK_WORD_LOCATION, JAVA_THREAD_HOLD_MONITOR_COUNT_LOCATION}; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/word/HotSpotOperation.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/word/HotSpotOperation.java index 3b1c02665350..878f20dd0dd1 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/word/HotSpotOperation.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/word/HotSpotOperation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ enum HotspotOpcode { FROM_POINTER, + FROM_COMPRESSED_POINTER, TO_KLASS_POINTER, TO_METHOD_POINTER, POINTER_EQ, diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/word/MetaspacePointer.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/word/MetaspacePointer.java index 9a1e4b826022..e4358ccbfa1f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/word/MetaspacePointer.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/word/MetaspacePointer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ */ package jdk.graal.compiler.hotspot.word; +import static jdk.graal.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.FROM_COMPRESSED_POINTER; import static jdk.graal.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.FROM_POINTER; import static jdk.graal.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.IS_NULL; @@ -48,6 +49,9 @@ public abstract class MetaspacePointer { @HotSpotOperation(opcode = FROM_POINTER) public abstract Word asWord(); + @HotSpotOperation(opcode = FROM_COMPRESSED_POINTER) + public abstract int asInt(); + /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in * bytes. diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/word/PointerCastNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/word/PointerCastNode.java index 16c3d4b24e43..a1e4f28415aa 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/word/PointerCastNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/word/PointerCastNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * 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,21 +30,21 @@ import jdk.graal.compiler.core.common.type.Stamp; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeClass; -import jdk.graal.compiler.nodes.spi.Canonicalizable; -import jdk.graal.compiler.nodes.spi.CanonicalizerTool; import jdk.graal.compiler.hotspot.word.HotSpotOperation.HotspotOpcode; import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.calc.FloatingNode; +import jdk.graal.compiler.nodes.spi.Canonicalizable; +import jdk.graal.compiler.nodes.spi.CanonicalizerTool; import jdk.graal.compiler.nodes.spi.LIRLowerable; import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; - import jdk.vm.ci.meta.Value; /** - * Cast between Word and metaspace pointers exposed by the {@link HotspotOpcode#FROM_POINTER} and - * {@link HotspotOpcode#TO_KLASS_POINTER} operations. + * Cast between Word and metaspace pointers exposed by the {@link HotspotOpcode#FROM_POINTER}, + * {@link HotspotOpcode#FROM_COMPRESSED_POINTER} and {@link HotspotOpcode#TO_KLASS_POINTER} + * operations. */ @NodeInfo(cycles = CYCLES_0, size = SIZE_0) public final class PointerCastNode extends FloatingNode implements Canonicalizable, LIRLowerable, Node.ValueNumberable { diff --git a/espresso/mx.espresso/suite.py b/espresso/mx.espresso/suite.py index ccbf65c49780..2c597c4409e9 100644 --- a/espresso/mx.espresso/suite.py +++ b/espresso/mx.espresso/suite.py @@ -222,7 +222,6 @@ "native": "shared_lib", "deliverable": "nespresso", "platformDependent": True, - "use_jdk_headers": True, "buildDependencies": [ "com.oracle.truffle.espresso.mokapot", ], @@ -283,7 +282,6 @@ "native": "shared_lib", "deliverable": "jvm", "platformDependent": True, - "use_jdk_headers": True, "os_arch": { "darwin": { "": { diff --git a/espresso/src/com.oracle.truffle.espresso.mokapot/include/jni.h b/espresso/src/com.oracle.truffle.espresso.mokapot/include/jni.h index 010bbc0ea020..303ed2d1530c 100644 --- a/espresso/src/com.oracle.truffle.espresso.mokapot/include/jni.h +++ b/espresso/src/com.oracle.truffle.espresso.mokapot/include/jni.h @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * 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 @@ -37,10 +39,15 @@ #include #include -/* jni_md.h contains the machine-dependent typedefs for jbyte, jint +/* jni_.h contains the machine-dependent typedefs for jbyte, jint and jlong */ - -#include "jni_md.h" +#if defined(_WIN32) +#include "jni_windows.h" +#elif defined(__linux__) || defined(__APPLE__) +#include "jni_unix.h" +#else +#error unknown platform +#endif #ifdef __cplusplus extern "C" { diff --git a/espresso/src/com.oracle.truffle.espresso.mokapot/include/jni_unix.h b/espresso/src/com.oracle.truffle.espresso.mokapot/include/jni_unix.h new file mode 100644 index 000000000000..6e583da7147e --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.mokapot/include/jni_unix.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ + +#ifndef _JAVASOFT_JNI_MD_H_ +#define _JAVASOFT_JNI_MD_H_ + +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif + +#ifndef JNIEXPORT + #if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) + #ifdef ARM + #define JNIEXPORT __attribute__((externally_visible,visibility("default"))) + #else + #define JNIEXPORT __attribute__((visibility("default"))) + #endif + #else + #define JNIEXPORT + #endif +#endif + +#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) + #ifdef ARM + #define JNIIMPORT __attribute__((externally_visible,visibility("default"))) + #else + #define JNIIMPORT __attribute__((visibility("default"))) + #endif +#else + #define JNIIMPORT +#endif + +#define JNICALL + +typedef int jint; +#ifdef _LP64 +typedef long jlong; +#else +typedef long long jlong; +#endif + +typedef signed char jbyte; + +#endif /* !_JAVASOFT_JNI_MD_H_ */ diff --git a/espresso/src/com.oracle.truffle.espresso.mokapot/include/jni_windows.h b/espresso/src/com.oracle.truffle.espresso.mokapot/include/jni_windows.h new file mode 100644 index 000000000000..b8c144fb047f --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.mokapot/include/jni_windows.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ + +#ifndef _JAVASOFT_JNI_MD_H_ +#define _JAVASOFT_JNI_MD_H_ + +#ifndef JNIEXPORT + #define JNIEXPORT __declspec(dllexport) +#endif +#define JNIIMPORT __declspec(dllimport) +#define JNICALL __stdcall + +// 'long' is always 32 bit on windows so this matches what jdk expects +typedef long jint; +typedef __int64 jlong; +typedef signed char jbyte; + +#endif /* !_JAVASOFT_JNI_MD_H_ */ diff --git a/espresso/src/com.oracle.truffle.espresso.native/include/jni.h b/espresso/src/com.oracle.truffle.espresso.native/include/jni.h index 010bbc0ea020..303ed2d1530c 100644 --- a/espresso/src/com.oracle.truffle.espresso.native/include/jni.h +++ b/espresso/src/com.oracle.truffle.espresso.native/include/jni.h @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * 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 @@ -37,10 +39,15 @@ #include #include -/* jni_md.h contains the machine-dependent typedefs for jbyte, jint +/* jni_.h contains the machine-dependent typedefs for jbyte, jint and jlong */ - -#include "jni_md.h" +#if defined(_WIN32) +#include "jni_windows.h" +#elif defined(__linux__) || defined(__APPLE__) +#include "jni_unix.h" +#else +#error unknown platform +#endif #ifdef __cplusplus extern "C" { diff --git a/espresso/src/com.oracle.truffle.espresso.native/include/jni_unix.h b/espresso/src/com.oracle.truffle.espresso.native/include/jni_unix.h new file mode 100644 index 000000000000..6e583da7147e --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.native/include/jni_unix.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ + +#ifndef _JAVASOFT_JNI_MD_H_ +#define _JAVASOFT_JNI_MD_H_ + +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif + +#ifndef JNIEXPORT + #if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) + #ifdef ARM + #define JNIEXPORT __attribute__((externally_visible,visibility("default"))) + #else + #define JNIEXPORT __attribute__((visibility("default"))) + #endif + #else + #define JNIEXPORT + #endif +#endif + +#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) + #ifdef ARM + #define JNIIMPORT __attribute__((externally_visible,visibility("default"))) + #else + #define JNIIMPORT __attribute__((visibility("default"))) + #endif +#else + #define JNIIMPORT +#endif + +#define JNICALL + +typedef int jint; +#ifdef _LP64 +typedef long jlong; +#else +typedef long long jlong; +#endif + +typedef signed char jbyte; + +#endif /* !_JAVASOFT_JNI_MD_H_ */ diff --git a/espresso/src/com.oracle.truffle.espresso.native/include/jni_windows.h b/espresso/src/com.oracle.truffle.espresso.native/include/jni_windows.h new file mode 100644 index 000000000000..b8c144fb047f --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.native/include/jni_windows.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ + +#ifndef _JAVASOFT_JNI_MD_H_ +#define _JAVASOFT_JNI_MD_H_ + +#ifndef JNIEXPORT + #define JNIEXPORT __declspec(dllexport) +#endif +#define JNIIMPORT __declspec(dllimport) +#define JNICALL __stdcall + +// 'long' is always 32 bit on windows so this matches what jdk expects +typedef long jint; +typedef __int64 jlong; +typedef signed char jbyte; + +#endif /* !_JAVASOFT_JNI_MD_H_ */ diff --git a/sdk/mx.sdk/mx_sdk_benchmark.py b/sdk/mx.sdk/mx_sdk_benchmark.py index b9feb879d9eb..5e09a196746d 100644 --- a/sdk/mx.sdk/mx_sdk_benchmark.py +++ b/sdk/mx.sdk/mx_sdk_benchmark.py @@ -1650,9 +1650,6 @@ def postprocessRunArgs(self, benchname, runArgs): def vmArgs(self, bmSuiteArgs): vm_args = super(RenaissanceBenchmarkSuite, self).vmArgs(bmSuiteArgs) - - # Renaissance issue #439 - vm_args.append("-Djava.security.manager=allow") return vm_args def createCommandLineArgs(self, benchmarks, bmSuiteArgs): diff --git a/sdk/mx.sdk/mx_sdk_vm.py b/sdk/mx.sdk/mx_sdk_vm.py index bd36e9a1ba12..a45d19face9f 100644 --- a/sdk/mx.sdk/mx_sdk_vm.py +++ b/sdk/mx.sdk/mx_sdk_vm.py @@ -1026,9 +1026,6 @@ def jlink_new_jdk(jdk, dst_jdk_dir, module_dists, ignore_dists, module_names = frozenset((m.name for m in modules)) all_module_names = frozenset(list(jdk_modules.keys())) | module_names - # Edit lib/security/default.policy in java.base - patched_java_base = _patch_default_security_policy(build_dir, jmods_dir, dst_jdk_dir) - # Now build the new JDK image with jlink jlink = [jdk.javac.replace('javac', 'jlink')] jlink_persist = [] @@ -1040,7 +1037,12 @@ def jlink_new_jdk(jdk, dst_jdk_dir, module_dists, ignore_dists, jlink.append('--add-modules=' + ','.join(_get_image_root_modules(root_module_names, module_names, jdk_modules.keys(), use_upgrade_module_path))) jlink_persist.append('--add-modules=jdk.internal.vm.ci') - module_path = patched_java_base + os.pathsep + jmods_dir + # Edit lib/security/default.policy in java.base if prior to JDK 24. + # GR-59085 deprecated the security manager in JDK 24 so no policy exists. + module_path = jmods_dir + if jdk.javaCompliance < '24': + patched_java_base = _patch_default_security_policy(build_dir, jmods_dir, dst_jdk_dir) + module_path = patched_java_base + os.pathsep + jmods_dir class TempJmods: """ diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsThreadCpuTimeSupport.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsThreadCpuTimeSupport.java index 50544324bce2..2c00384c01e6 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsThreadCpuTimeSupport.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsThreadCpuTimeSupport.java @@ -55,7 +55,7 @@ public long getThreadCpuTime(IsolateThread isolateThread, boolean includeSystemT return getThreadCpuTime(hThread, includeSystemTime); } - @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-23+26/src/hotspot/os/windows/os_windows.cpp#L4960-L4976") + @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+24/src/hotspot/os/windows/os_windows.cpp#L4787-L4803") @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) private static long getThreadCpuTime(HANDLE hThread, boolean includeSystemTime) { FILETIME create = StackValue.get(FILETIME.class); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java index 7b26c78e55b8..6a2803c84c4d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java @@ -47,12 +47,12 @@ public class LibCHelper { public static class Locale { @CFunction(transition = Transition.TO_NATIVE) @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+17/src/java.base/unix/native/libjava/java_props_md.c#L93-L357") - @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+17/src/java.base/windows/native/libjava/java_props_md.c#L321-L715") + @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+24/src/java.base/windows/native/libjava/java_props_md.c#L321-L713") public static native CCharPointerPointer parseDisplayLocale(); @CFunction(transition = Transition.TO_NATIVE) @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+17/src/java.base/unix/native/libjava/java_props_md.c#L93-L357") - @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+17/src/java.base/windows/native/libjava/java_props_md.c#L321-L715") + @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+24/src/java.base/windows/native/libjava/java_props_md.c#L321-L713") public static native CCharPointerPointer parseFormatLocale(); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/attach/AttachListenerThread.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/attach/AttachListenerThread.java index 718357e81510..b824b39dd37d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/attach/AttachListenerThread.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/attach/AttachListenerThread.java @@ -96,7 +96,7 @@ private static void handleJcmd(AttachOperation op) { } @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+18/src/hotspot/share/services/diagnosticFramework.cpp#L383-L420") - @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+18/src/hotspot/share/services/diagnosticFramework.cpp#L422-L439") + @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+24/src/hotspot/share/services/diagnosticFramework.cpp#L422-L439") private static String parseAndExecute(String input) throws Throwable { String[] args = StringUtil.split(input, " "); String cmdName = args[0]; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/container/ContainerLibrary.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/container/ContainerLibrary.java index fba1a45c9be1..7ed5d698a66b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/container/ContainerLibrary.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/container/ContainerLibrary.java @@ -48,9 +48,9 @@ @CContext(ContainerLibraryDirectives.class) @CLibrary(value = "svm_container", requireStatic = true, dependsOn = "m") // The following annotations are for files in `src/hotspot`, which are copied from the JDK -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/java.base/share/native/include/jni.h") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/java.base/unix/native/include/jni_md.h") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/linux/cgroupSubsystem_linux.cpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+24/src/java.base/share/native/include/jni.h") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+24/src/java.base/unix/native/include/jni_md.h") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+24/src/hotspot/os/linux/cgroupSubsystem_linux.cpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/linux/cgroupSubsystem_linux.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/linux/cgroupUtil_linux.cpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/linux/cgroupUtil_linux.hpp") @@ -63,16 +63,16 @@ @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+21/src/hotspot/os/linux/os_linux.cpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/linux/os_linux.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/linux/os_linux.inline.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/posix/include/jvm_md.h") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+20/src/hotspot/os/posix/os_posix.cpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+24/src/hotspot/os/posix/include/jvm_md.h") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+24/src/hotspot/os/posix/os_posix.cpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+20/src/hotspot/os/posix/os_posix.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/posix/os_posix.inline.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/memory/allocation.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/memory/allocation.inline.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/memory/allStatic.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/nmt/memTag.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+22/src/hotspot/share/runtime/os.cpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+20/src/hotspot/share/runtime/os.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+24/src/hotspot/share/runtime/os.cpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+24/src/hotspot/share/runtime/os.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/runtime/os.inline.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/utilities/checkedCast.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/utilities/compilerWarnings_gcc.hpp") @@ -85,7 +85,7 @@ // The following annotations are for files in `src/svm`, which are completely customized for SVM @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/logging/log.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/memory/allocation.cpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+19/src/hotspot/share/runtime/globals.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+24/src/hotspot/share/runtime/globals.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+22/src/hotspot/share/utilities/debug.cpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/utilities/debug.hpp") public class ContainerLibrary { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/AccessControllerUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/AccessControllerUtil.java index 38b2152b4ffa..188662982abb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/AccessControllerUtil.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/AccessControllerUtil.java @@ -29,9 +29,10 @@ import java.util.ArrayDeque; import java.util.Objects; -import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; + /** * Stack for storing AccessControlContexts. Used in conjunction with * {@code StackAccessControlContextVisitor}. @@ -104,10 +105,7 @@ public class AccessControllerUtil { public static final AccessControlContext DISALLOWED_CONTEXT_MARKER; static { - try { - DISALLOWED_CONTEXT_MARKER = ReflectionUtil.lookupConstructor(AccessControlContext.class, ProtectionDomain[].class, boolean.class).newInstance(new ProtectionDomain[0], true); - } catch (ReflectiveOperationException ex) { - throw VMError.shouldNotReachHere(ex); - } + DISALLOWED_CONTEXT_MARKER = JavaVersionUtil.JAVA_SPEC > 21 ? null + : ReflectionUtil.newInstance(ReflectionUtil.lookupConstructor(AccessControlContext.class, ProtectionDomain[].class, boolean.class), new ProtectionDomain[0], true); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java index 0e414850543c..d6e684b47a7e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java @@ -428,7 +428,7 @@ private static String getProperty(String key, String def) { * passed to the image builder. */ @Alias @RecomputeFieldValue(kind = Kind.FromAlias, isFinal = true) // - private static int allowSecurityManager = 1; + @TargetElement(onlyWith = JDK21OrEarlier.class) private static int allowSecurityManager = 1; /** * We do not support the {@link SecurityManager} so this method must throw a @@ -440,6 +440,7 @@ private static String getProperty(String key, String def) { */ @Substitute @SuppressWarnings({"removal", "javadoc"}) + @TargetElement(onlyWith = JDK21OrEarlier.class) private static void setSecurityManager(SecurityManager sm) { if (sm != null) { /* Read the property collected at isolate creation as that is what happens on the JVM */ diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java index d48c3330709e..23dc62dcaca2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java @@ -75,7 +75,7 @@ * All security checks are disabled. */ -@TargetClass(java.security.AccessController.class) +@TargetClass(value = java.security.AccessController.class, onlyWith = JDK21OrEarlier.class) @Platforms(InternalPlatform.NATIVE_ONLY.class) @SuppressWarnings({"unused"}) final class Target_java_security_AccessController { @@ -432,11 +432,11 @@ public boolean test(Class originalClass) { } } -@TargetClass(value = java.security.Policy.class, innerClass = "PolicyInfo") +@TargetClass(value = java.security.Policy.class, innerClass = "PolicyInfo", onlyWith = JDK21OrEarlier.class) final class Target_java_security_Policy_PolicyInfo { } -@TargetClass(java.security.Policy.class) +@TargetClass(value = java.security.Policy.class, onlyWith = JDK21OrEarlier.class) final class Target_java_security_Policy { @Delete // @@ -503,7 +503,7 @@ public boolean implies(ProtectionDomain domain, Permission permission) { * version is more fool-proof in case someone manually registers security providers for reflective * instantiation. */ -@TargetClass(className = "sun.security.provider.PolicySpiFile") +@TargetClass(className = "sun.security.provider.PolicySpiFile", onlyWith = JDK21OrEarlier.class) @SuppressWarnings({"unused", "static-method", "deprecation"}) final class Target_sun_security_provider_PolicySpiFile { @@ -536,7 +536,7 @@ private void engineRefresh() { } @Delete("Substrate VM does not use SecurityManager, so loading a security policy file would be misleading") -@TargetClass(className = "sun.security.provider.PolicyFile") +@TargetClass(className = "sun.security.provider.PolicyFile", onlyWith = JDK21OrEarlier.class) final class Target_sun_security_provider_PolicyFile { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_security_AccessControlContext.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_security_AccessControlContext.java index cfd7d956e86a..1602bd8bf127 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_security_AccessControlContext.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_security_AccessControlContext.java @@ -34,7 +34,7 @@ import sun.security.util.Debug; -@TargetClass(java.security.AccessControlContext.class) +@TargetClass(value = java.security.AccessControlContext.class, onlyWith = JDK21OrEarlier.class) final class Target_java_security_AccessControlContext { @Alias // diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFunctionPointerTypes.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFunctionPointerTypes.java index 95420cac519d..63ffc9533463 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFunctionPointerTypes.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFunctionPointerTypes.java @@ -262,6 +262,11 @@ public interface IsSameObjectFunctionPointer extends CFunctionPointer { boolean invoke(JNIEnvironment env, JNIObjectHandle obj1, JNIObjectHandle obj2); } + public interface MonitorEnterExitFunctionPointer extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(JNIEnvironment env, JNIObjectHandle obj); + } + private JNIFunctionPointerTypes() { } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNINativeInterface.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNINativeInterface.java index 3351724ed326..b30e7b449ac1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNINativeInterface.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNINativeInterface.java @@ -63,6 +63,7 @@ import com.oracle.svm.core.jni.headers.JNIFunctionPointerTypes.IsAssignableFromFunctionPointer; import com.oracle.svm.core.jni.headers.JNIFunctionPointerTypes.IsInstanceOfFunctionPointer; import com.oracle.svm.core.jni.headers.JNIFunctionPointerTypes.IsSameObjectFunctionPointer; +import com.oracle.svm.core.jni.headers.JNIFunctionPointerTypes.MonitorEnterExitFunctionPointer; import com.oracle.svm.core.jni.headers.JNIFunctionPointerTypes.NewByteArrayFunctionPointer; import com.oracle.svm.core.jni.headers.JNIFunctionPointerTypes.NewGlobalRefFunctionPointer; import com.oracle.svm.core.jni.headers.JNIFunctionPointerTypes.NewObjectAFunctionPointer; @@ -1372,16 +1373,16 @@ public interface JNINativeInterface extends PointerBase { void setUnregisterNatives(CFunctionPointer p); @CField - CFunctionPointer getMonitorEnter(); + MonitorEnterExitFunctionPointer getMonitorEnter(); @CField - void setMonitorEnter(CFunctionPointer p); + void setMonitorEnter(MonitorEnterExitFunctionPointer p); @CField - CFunctionPointer getMonitorExit(); + MonitorEnterExitFunctionPointer getMonitorExit(); @CField - void setMonitorExit(CFunctionPointer p); + void setMonitorExit(MonitorEnterExitFunctionPointer p); @CField CFunctionPointer getGetJavaVM(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java index 2e034ef9b3ba..8a7c56564940 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java @@ -36,6 +36,7 @@ import com.oracle.svm.core.jfr.events.JavaMonitorWaitEvent; import com.oracle.svm.core.thread.JavaThreads; import com.oracle.svm.core.util.BasedOnJDKClass; +import com.oracle.svm.core.util.BasedOnJDKFile; import jdk.internal.misc.Unsafe; @@ -282,6 +283,7 @@ protected int getSpinAttempts(int parks) { // see AbstractQueuedLongSynchronizer.acquire(Node, long, false, false, false, 0L) @SuppressWarnings("all") + @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+24/src/hotspot/share/runtime/objectMonitor.cpp#L895-L930") final int acquire(Node node, long arg) { Thread current = Thread.currentThread(); /* Spinning logic is SVM-specific. */ @@ -289,6 +291,15 @@ final int acquire(Node node, long arg) { int spins = getSpinAttempts(parks); boolean first = false; Node pred = null; // predecessor of node when enqueued + long recheckNanos = -1; + if (JavaThreads.isCurrentThreadVirtualAndPinned()) { + /* + * Do not park indefinitely and instead periodically retry acquiring the monitor. This + * avoids liveness trouble when all carrier threads have virtual threads pinned to them + * and so a queued successor cannot be scheduled when it is unparked. + */ + recheckNanos = 1_000_000; + } for (;;) { if (!first && (pred = (node == null) ? null : node.prev) != null && !(first = (head == pred))) { @@ -353,7 +364,16 @@ final int acquire(Node node, long arg) { parks++; spins = getSpinAttempts(parks); try { - LockSupport.park(this); + if (recheckNanos == -1) { + LockSupport.park(this); + } else { + LockSupport.parkNanos(this, recheckNanos); + if (tryAcquire(arg)) { + cancelAcquire(node); + return 1; + } + recheckNanos = Math.min(recheckNanos << 3, 1_000_000_000); + } } catch (Error | RuntimeException ex) { cancelAcquire(node); // cancel & rethrow throw ex; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java index 7a458f0a0c65..49508dcec039 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java @@ -113,12 +113,16 @@ public class MultiThreadedMonitorSupport extends MonitorSupport { static { try { + HashMap, Boolean> monitorTypes = new HashMap<>(); /* * The com.oracle.svm.core.WeakIdentityHashMap used to model the * com.oracle.svm.core.monitor.MultiThreadedMonitorSupport#additionalMonitors map uses - * java.lang.ref.ReferenceQueue internally. + * java.lang.ref.ReferenceQueue internally. The ReferenceQueue uses the inner static + * class Lock for all its locking needs. */ - HashMap, Boolean> monitorTypes = new HashMap<>(); + if (JavaVersionUtil.JAVA_SPEC > 21) { + monitorTypes.put(Class.forName("java.lang.ref.ReferenceQueue$Lock"), false); + } /* The WeakIdentityHashMap also synchronizes on its internal ReferenceQueue field. */ monitorTypes.put(java.lang.ref.ReferenceQueue.class, false); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java index 2b19371ee09e..7edad49d9e46 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java @@ -382,7 +382,9 @@ static void initializeNewThread( PlatformThreads.setThreadStatus(fromTarget(tjlt), ThreadStatus.NEW); - tjlt.inheritedAccessControlContext = acc != null ? acc : AccessController.getContext(); + if (JavaVersionUtil.JAVA_SPEC == 21) { + tjlt.inheritedAccessControlContext = acc != null ? acc : AccessController.getContext(); + } initNewThreadLocalsAndLoader(tjlt, inheritThreadLocals, parent); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreadsFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreadsFeature.java index c76db9be11cd..ac80b9c4a0d6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreadsFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreadsFeature.java @@ -25,12 +25,18 @@ package com.oracle.svm.core.thread; import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.util.ReflectionUtil; + +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; public abstract class JavaThreadsFeature implements InternalFeature { protected static long threadId(Thread thread) { if (thread == PlatformThreads.singleton().mainThread) { - return 1; + if (JavaVersionUtil.JAVA_SPEC <= 21) { + return 1; + } + return ReflectionUtil.readStaticField(Thread.class, "PRIMORDIAL_TID"); } return JavaThreads.getThreadId(thread); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java index 4ba7f1453517..26385ae097cf 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java @@ -52,6 +52,7 @@ import jdk.graal.compiler.api.directives.GraalDirectives; import jdk.graal.compiler.replacements.ReplacementsUtil; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; @TargetClass(Thread.class) @SuppressWarnings({"unused"}) @@ -115,6 +116,7 @@ public final class Target_java_lang_Thread { */ @Alias // @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) // + @TargetElement(onlyWith = JDK21OrEarlier.class) // public AccessControlContext inheritedAccessControlContext; @Alias // @@ -215,6 +217,7 @@ void setCurrentThread(Thread thread) { @Substitute @SuppressWarnings({"unused"}) @Platforms(InternalPlatform.NATIVE_ONLY.class) + @TargetElement(onlyWith = JDK21OrEarlier.class) private Target_java_lang_Thread( ThreadGroup g, String name, @@ -234,6 +237,27 @@ private Target_java_lang_Thread( this.scopedValueBindings = NEW_THREAD_BINDINGS; } + @Substitute + @Platforms(InternalPlatform.NATIVE_ONLY.class) + @TargetElement(onlyWith = JDKLatest.class) + private Target_java_lang_Thread( + ThreadGroup g, + String name, + int characteristics, + Runnable target, + long stackSize) { + /* Non-0 instance field initialization. */ + this.interruptLock = new Object(); + /* Injected Target_java_lang_Thread instance field initialization. */ + this.threadData = new ThreadData(); + + String nameLocal = (name != null) ? name : genThreadName(); + boolean inheritThreadLocals = (characteristics & NO_INHERIT_THREAD_LOCALS) == 0; + JavaThreads.initializeNewThread(this, g, target, nameLocal, stackSize, null, inheritThreadLocals); + + this.scopedValueBindings = NEW_THREAD_BINDINGS; + } + @Substitute static String genThreadName() { int threadNum = JavaThreads.JavaThreadNumberSingleton.singleton().threadInitNumber.incrementAndGet(); @@ -252,7 +276,9 @@ private Target_java_lang_Thread(String name, int characteristics, boolean bound) this.name = (name != null) ? name : ""; this.tid = Target_java_lang_Thread_ThreadIdentifiers.next(); - this.inheritedAccessControlContext = Target_java_lang_Thread_Constants.NO_PERMISSIONS_ACC; + if (JavaVersionUtil.JAVA_SPEC == 21) { + this.inheritedAccessControlContext = Target_java_lang_Thread_Constants.NO_PERMISSIONS_ACC; + } boolean inheritThreadLocals = (characteristics & NO_INHERIT_THREAD_LOCALS) == 0; JavaThreads.initNewThreadLocalsAndLoader(this, inheritThreadLocals, Thread.currentThread()); @@ -538,6 +564,7 @@ boolean isTerminated() { final class Target_java_lang_Thread_Constants { // Checkstyle: stop @SuppressWarnings("removal") // + @TargetElement(onlyWith = JDK21OrEarlier.class) // @Alias static AccessControlContext NO_PERMISSIONS_ACC; @Alias static ThreadGroup VTHREAD_GROUP; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_VirtualThread.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_VirtualThread.java index 9bc620107258..98b4ed23ece4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_VirtualThread.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_VirtualThread.java @@ -61,8 +61,7 @@ public final class Target_java_lang_VirtualThread { // Checkstyle: stop @Alias static int NEW; @Alias static int STARTED; - @Alias // - @TargetElement(onlyWith = JDK21OrEarlier.class) static int RUNNABLE; + @TargetElement(onlyWith = JDK21OrEarlier.class) @Alias static int RUNNABLE; @Alias static int RUNNING; @Alias static int PARKING; @Alias static int PARKED; @@ -75,6 +74,13 @@ public final class Target_java_lang_VirtualThread { @TargetElement(onlyWith = JDKLatest.class) @Alias static int TIMED_PARKED; @TargetElement(onlyWith = JDKLatest.class) @Alias static int TIMED_PINNED; @TargetElement(onlyWith = JDKLatest.class) @Alias static int UNPARKED; + @TargetElement(onlyWith = JDKLatest.class) @Alias static int BLOCKING; + @TargetElement(onlyWith = JDKLatest.class) @Alias static int BLOCKED; + @TargetElement(onlyWith = JDKLatest.class) @Alias static int UNBLOCKED; + @TargetElement(onlyWith = JDKLatest.class) @Alias static int WAITING; + @TargetElement(onlyWith = JDKLatest.class) @Alias static int WAIT; + @TargetElement(onlyWith = JDKLatest.class) @Alias static int TIMED_WAITING; + @TargetElement(onlyWith = JDKLatest.class) @Alias static int TIMED_WAIT; @Alias static Target_jdk_internal_vm_ContinuationScope VTHREAD_SCOPE; /** @@ -111,6 +117,14 @@ public final class Target_java_lang_VirtualThread { */ @Inject @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = NondefaultSchedulerSupplier.class) // private Executor nondefaultScheduler; + + @TargetElement(onlyWith = JDKLatest.class) @Alias volatile int state; + + // With our monitor implementation, we do not use these fields. + @TargetElement(onlyWith = JDKLatest.class) @Delete volatile Target_java_lang_VirtualThread next; + @TargetElement(onlyWith = JDKLatest.class) @Alias @InjectAccessors(AlwaysFalseAccessor.class) boolean blockPermit; + @TargetElement(onlyWith = JDKLatest.class) @Alias @InjectAccessors(AlwaysFalseAccessor.class) boolean onWaitingList; + @TargetElement(onlyWith = JDKLatest.class) @Alias @InjectAccessors(AlwaysFalseAccessor.class) boolean notified; // Checkstyle: resume @Alias @@ -124,6 +138,17 @@ public final class Target_java_lang_VirtualThread { @TargetElement(onlyWith = JDKLatest.class) private static native ScheduledExecutorService[] createDelayedTaskSchedulers(); + @SuppressWarnings("unused") + private static final class AlwaysFalseAccessor { + static boolean get(Target_java_lang_VirtualThread vt) { + return false; + } + + static void set(Target_java_lang_VirtualThread vt, boolean value) { + assert !value; + } + } + private static final class DefaultSchedulerAccessor { private static volatile ForkJoinPool defaultScheduler; @@ -258,6 +283,12 @@ private static void notifyJvmtiDisableSuspend(boolean enter) { // unimplemented (GR-51158) } + @Substitute + @SuppressWarnings("unused") + @TargetElement(onlyWith = JDKLatest.class) + private static void postPinnedEvent(String op) { + } + @Alias volatile Thread carrierThread; @Alias volatile Target_sun_nio_ch_Interruptible nioBlocker; @@ -298,6 +329,10 @@ boolean getAndClearInterruptJDK21() { @TargetElement(onlyWith = JDKLatest.class) native void enableSuspendAndPreempt(); + @Alias + @TargetElement(onlyWith = JDKLatest.class) + native Object carrierThreadAccessLock(); + @Alias private native void setCarrierThread(Target_java_lang_Thread carrier); @@ -346,9 +381,33 @@ void unmountJDK21() { @Alias native int state(); + @Substitute + @TargetElement(onlyWith = JDKLatest.class) + void setState(int s) { + assert s != BLOCKING && s != BLOCKED && s != UNBLOCKED && s != WAITING && s != WAIT && s != TIMED_WAIT && s != TIMED_WAITING // + : "states should never be reached with our monitor implementation"; + state = s; + } + + @Substitute + @TargetElement(onlyWith = JDKLatest.class) + @SuppressWarnings({"static-method", "unused"}) + void waitTimeoutExpired(byte seqNo) { + throw VMError.shouldNotReachHere("not used in our monitor implementation"); + } + + @Delete + @TargetElement(onlyWith = JDKLatest.class) + static native void unblockVirtualThreads(); + + @Delete + @TargetElement(onlyWith = JDKLatest.class) + private static native Target_java_lang_VirtualThread takeVirtualThreadListToUnblock(); + /** Needed for handling monitor-specific states. */ @Substitute @TargetElement(onlyWith = JDKLatest.class) + @SuppressWarnings("hiding") Thread.State threadState() { int state = state() & ~SUSPENDED; if (state == NEW) { @@ -365,7 +424,7 @@ Thread.State threadState() { if (Thread.currentThread() != asThread(this)) { disableSuspendAndPreempt(); try { - synchronized (asTarget(this).interruptLock) { + synchronized (carrierThreadAccessLock()) { Thread carrier = this.carrierThread; if (carrier != null) { return asTarget(carrier).threadState(); @@ -378,25 +437,25 @@ Thread.State threadState() { return Thread.State.RUNNABLE; } else if (state == PARKING || state == YIELDING) { return Thread.State.RUNNABLE; - } else if (state == PARKED || state == PINNED) { - int parkedThreadStatus = MonitorSupport.singleton().getParkedThreadStatus(asThread(this), false); + } else if (state == PARKED || state == PINNED || state == TIMED_PARKED || state == TIMED_PINNED) { + boolean timed = (state == TIMED_PARKED || state == TIMED_PINNED); + int parkedThreadStatus = MonitorSupport.singleton().getParkedThreadStatus(asThread(this), timed); switch (parkedThreadStatus) { case ThreadStatus.BLOCKED_ON_MONITOR_ENTER: return Thread.State.BLOCKED; case ThreadStatus.PARKED: case ThreadStatus.IN_OBJECT_WAIT: return Thread.State.WAITING; + case ThreadStatus.PARKED_TIMED: + case ThreadStatus.IN_OBJECT_WAIT_TIMED: + return Thread.State.TIMED_WAITING; default: throw VMError.shouldNotReachHereUnexpectedInput(parkedThreadStatus); // ExcludeFromJacocoGeneratedReport } } else if (state == TERMINATED) { return Thread.State.TERMINATED; - } else { - if (state == TIMED_PARKING) { - return Thread.State.RUNNABLE; - } else if (state == TIMED_PARKED || state == TIMED_PINNED) { - return Thread.State.TIMED_WAITING; - } + } else if (state == TIMED_PARKING) { + return Thread.State.RUNNABLE; } throw new InternalError(); } @@ -404,6 +463,7 @@ Thread.State threadState() { /** Needed because {@link #disableSuspendAndPreempt()} does not exist on JDK 21. */ @Substitute @TargetElement(name = "threadState", onlyWith = JDK21OrEarlier.class) + @SuppressWarnings("hiding") Thread.State threadStateJDK21() { int state = state() & ~SUSPENDED; if (state == NEW) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java index dd5755cac711..1132f74b24c7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java @@ -166,8 +166,12 @@ public static class Options { CertPathBuilder.class, CertPathValidator.class, CertStore.class, CertificateFactory.class, Cipher.class, Configuration.class, KeyAgreement.class, KeyFactory.class, KeyGenerator.class, KeyManagerFactory.class, KeyPairGenerator.class, - KeyStore.class, Mac.class, MessageDigest.class, Policy.class, SSLContext.class, + KeyStore.class, Mac.class, MessageDigest.class, SSLContext.class, SecretKeyFactory.class, SecureRandom.class, Signature.class, TrustManagerFactory.class)); + if (JavaVersionUtil.JAVA_SPEC <= 21) { + // JDK-8338411: Implement JEP 486: Permanently Disable the Security Manager + classList.add(Policy.class); + } if (ModuleLayer.boot().findModule("java.security.sasl").isPresent()) { classList.add(ReflectionUtil.lookupClass(false, "javax.security.sasl.SaslClientFactory")); @@ -634,6 +638,7 @@ private void registerServices(DuringAnalysisAccess access, Object trigger, Strin private void doRegisterServices(DuringAnalysisAccess access, Object trigger, String serviceType) { try (TracingAutoCloseable ignored = trace(access, trigger, serviceType)) { Set services = availableServices.get(serviceType); + VMError.guarantee(services != null); for (Service service : services) { registerService(access, service); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/AccessControlContextReplacerFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/AccessControlContextReplacerFeature.java index e6c26597d24f..53535d322192 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/AccessControlContextReplacerFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/AccessControlContextReplacerFeature.java @@ -43,6 +43,11 @@ @SuppressWarnings({"unused"}) class AccessControlContextReplacerFeature implements InternalFeature { + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return JavaVersionUtil.JAVA_SPEC == 21; + } + static Map allowedContexts = new HashMap<>(); static void allowContextIfExists(String className, String fieldName) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNINativeCallWrapperMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNINativeCallWrapperMethod.java index e0244cb2bf27..296bb46b9069 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNINativeCallWrapperMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNINativeCallWrapperMethod.java @@ -118,6 +118,27 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos callAddress = kit.invokeNativeCallAddress(kit.createObject(linkage)); } + List javaArguments = kit.getInitialArguments(); + + /* + * Acquire the lock upfront because when in a virtual thread, contention could cause + * migration to a different carrier thread with a different JNI environment and local handle + * set before the native call. + */ + if (getOriginal().isSynchronized()) { + ValueNode monitorObject; + if (method.isStatic()) { + JavaConstant hubConstant = (JavaConstant) kit.getConstantReflection().asObjectHub(method.getDeclaringClass()); + monitorObject = ConstantNode.forConstant(hubConstant, kit.getMetaAccess(), kit.getGraph()); + } else { + monitorObject = kit.maybeCreateExplicitNullCheck(javaArguments.get(0)); + } + MonitorIdNode monitorId = kit.getGraph().add(new MonitorIdNode(kit.getFrameState().lockDepth(false))); + MonitorEnterNode monitorEnter = kit.append(new MonitorEnterNode(monitorObject, monitorId)); + kit.getFrameState().pushLock(monitorEnter.object(), monitorEnter.getMonitorId()); + monitorEnter.setStateAfter(kit.getFrameState().create(kit.bci(), monitorEnter)); + } + ValueNode environment = kit.invokeEnvironment(); /* After the JNI prologue, we must not invoke methods that may throw an exception. */ @@ -125,7 +146,6 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos AnalysisType javaReturnType = method.getSignature().getReturnType(); List javaArgumentTypes = method.toParameterList(); - List javaArguments = kit.getInitialArguments(); List jniArguments = new ArrayList<>(2 + javaArguments.size()); List jniArgumentTypes = new ArrayList<>(2 + javaArguments.size()); @@ -159,21 +179,6 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos jniReturnType = objectHandleType; } - /* Thrown exceptions may cause a memory leak, see GR-54276. */ - if (getOriginal().isSynchronized()) { - ValueNode monitorObject; - if (method.isStatic()) { - JavaConstant hubConstant = (JavaConstant) kit.getConstantReflection().asObjectHub(method.getDeclaringClass()); - monitorObject = ConstantNode.forConstant(hubConstant, kit.getMetaAccess(), kit.getGraph()); - } else { - monitorObject = kit.maybeCreateExplicitNullCheck(javaArguments.get(0)); - } - MonitorIdNode monitorId = kit.getGraph().add(new MonitorIdNode(kit.getFrameState().lockDepth(false))); - MonitorEnterNode monitorEnter = kit.append(new MonitorEnterNode(monitorObject, monitorId)); - kit.getFrameState().pushLock(monitorEnter.object(), monitorEnter.getMonitorId()); - monitorEnter.setStateAfter(kit.getFrameState().create(kit.bci(), monitorEnter)); - } - kit.getFrameState().clearLocals(); var jniSignature = ResolvedSignature.fromList(jniArgumentTypes, jniReturnType); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java index 485fc871aeb9..01699fc87374 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java @@ -121,10 +121,16 @@ public void duringSetup(DuringSetupAccess access) { if (JavaVersionUtil.JAVA_SPEC >= 22) { try { Class referencedKeySetClass = ReflectionUtil.lookupClass("jdk.internal.util.ReferencedKeySet"); - Method create = ReflectionUtil.lookupMethod(referencedKeySetClass, "create", boolean.class, boolean.class, Supplier.class); // The following call must match the static initializer of MethodType#internTable. - runtimeMethodTypeInternTable = create.invoke(null, - /* isSoft */ false, /* useNativeQueue */ true, (Supplier) () -> new ConcurrentHashMap<>(512)); + if (JavaVersionUtil.JAVA_SPEC >= 24) { + Method create = ReflectionUtil.lookupMethod(referencedKeySetClass, "create", boolean.class, Supplier.class); + runtimeMethodTypeInternTable = create.invoke(null, + /* isSoft */ false, (Supplier) () -> new ConcurrentHashMap<>(512)); + } else { + Method create = ReflectionUtil.lookupMethod(referencedKeySetClass, "create", boolean.class, boolean.class, Supplier.class); + runtimeMethodTypeInternTable = create.invoke(null, + /* isSoft */ false, /* useNativeQueue */ true, (Supplier) () -> new ConcurrentHashMap<>(512)); + } referencedKeySetAdd = ReflectionUtil.lookupMethod(referencedKeySetClass, "add", Object.class); } catch (ReflectiveOperationException e) { throw VMError.shouldNotReachHere(e); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/util/IdentityHashCodeUtil.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/util/IdentityHashCodeUtil.java index 2075875b49b5..8fa1b77b6bc7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/util/IdentityHashCodeUtil.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/util/IdentityHashCodeUtil.java @@ -52,7 +52,7 @@ public class IdentityHashCodeUtil { static { unsafe = Unsafe.getUnsafe(); config = GraalAccess.getGraalCapability(GraalHotSpotVMConfig.class); - hashCodeMask = NumUtil.getNbitNumberLong(31) << config.identityHashCodeShift; + hashCodeMask = NumUtil.getNbitNumberLong(31) << config.markWordHashCodeShift; } /** @@ -116,7 +116,7 @@ private static int readIdentityHashCode(long markWord) { /* * See HotSpotHashCodeSnippets for explanation. */ - long lockBits = markWord & config.lockMaskInPlace; + long lockBits = markWord & config.markWordLockMaskInPlace; boolean containsHashCode; if (config.lockingMode == config.lockingModeLightweight) { containsHashCode = lockBits != config.monitorValue; @@ -124,7 +124,7 @@ private static int readIdentityHashCode(long markWord) { containsHashCode = lockBits == config.unlockedValue; } if (containsHashCode) { - int hashcode = (int) (markWord >>> config.identityHashCodeShift); + int hashcode = (int) ((markWord & hashCodeMask) >>> config.markWordHashCodeShift); if (hashcode == config.uninitializedIdentityHashCodeValue) { return UNINITIALIZED; } @@ -138,11 +138,12 @@ private static int readIdentityHashCode(long markWord) { * @return true if the object's identity hash code was set. */ private static boolean trySetIdentityHashCode(Object obj, long originalMarkWord, int hashCode) { + long hashInPlace = (((long) hashCode) << config.markWordHashCodeShift) & hashCodeMask; long newMarkWord; if (config.uninitializedIdentityHashCodeValue == 0) { - newMarkWord = originalMarkWord | (((long) hashCode) << config.identityHashCodeShift); + newMarkWord = originalMarkWord | hashInPlace; } else { - newMarkWord = (originalMarkWord & (~hashCodeMask)) | (((long) hashCode) << config.identityHashCodeShift); + newMarkWord = (originalMarkWord & (~hashCodeMask)) | hashInPlace; } return unsafe.compareAndSetLong(obj, config.markOffset, originalMarkWord, newMarkWord); } diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestJavaLevelVirtualThreadEvents.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestJavaLevelVirtualThreadEvents.java index 1810859671ab..6a0e950e19d8 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestJavaLevelVirtualThreadEvents.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestJavaLevelVirtualThreadEvents.java @@ -41,6 +41,7 @@ import com.oracle.svm.core.thread.Target_jdk_internal_vm_Continuation; import com.oracle.svm.test.jfr.events.StringEvent; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.jfr.Recording; import jdk.jfr.consumer.RecordedEvent; import jdk.jfr.consumer.RecordedThread; @@ -54,7 +55,12 @@ public class TestJavaLevelVirtualThreadEvents extends JfrRecordingTest { @Test public void test() throws Throwable { - String[] events = new String[]{"jdk.ThreadSleep", "jdk.VirtualThreadStart", "jdk.VirtualThreadEnd", "jdk.VirtualThreadPinned", "com.jfr.String"}; + String[] events; + if (JavaVersionUtil.JAVA_SPEC <= 21) { + events = new String[]{"jdk.ThreadSleep", "jdk.VirtualThreadStart", "jdk.VirtualThreadEnd", "jdk.VirtualThreadPinned", "com.jfr.String"}; + } else { + events = new String[]{"jdk.ThreadSleep", "jdk.VirtualThreadStart", "jdk.VirtualThreadEnd", "com.jfr.String"}; + } Recording recording = startRecording(events); Runnable r = () -> { try { diff --git a/vm/ci/ci_includes/vm-native.jsonnet b/vm/ci/ci_includes/vm-native.jsonnet index 6681a9cad43b..09fa53c80073 100644 --- a/vm/ci/ci_includes/vm-native.jsonnet +++ b/vm/ci/ci_includes/vm-native.jsonnet @@ -83,8 +83,7 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; vm.vm_java_Latest + vm_common.vm_base('linux', 'amd64', 'gate') + { gate_tag_suffix: '-quickbuild', } + truffle_native, - vm.vm_java_21 + vm_common.vm_base('linux', 'amd64', 'daily') + truffle_native_tck, - vm.vm_java_Latest + vm_common.vm_base('linux', 'amd64', 'gate') + truffle_native_tck, + vm.vm_java_21 + vm_common.vm_base('linux', 'amd64', 'gate') + truffle_native_tck, vm.vm_java_21 + vm_common.vm_base('linux', 'amd64', 'daily') + truffle_jvm, vm.vm_java_Latest + vm_common.vm_base('linux', 'amd64', 'gate') + truffle_jvm, vm.vm_java_21 + vm_common.vm_base('linux', 'amd64', 'daily') + truffle_maven_downloader,