diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/FinalFieldBarrierNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/FinalFieldBarrierNode.java index 2a4c118ade9a..59bdb72bb8d5 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/FinalFieldBarrierNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/FinalFieldBarrierNode.java @@ -76,4 +76,7 @@ public void lower(LoweringTool tool) { */ graph().replaceFixedWithFixed(this, graph().add(new MembarNode(MembarNode.FenceKind.CONSTRUCTOR_FREEZE))); } + + @NodeIntrinsic + public static native void finalFieldBarrier(Object object); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CompactingOldGeneration.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CompactingOldGeneration.java index d219f81d010c..1b12444bdb88 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CompactingOldGeneration.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CompactingOldGeneration.java @@ -139,6 +139,11 @@ void absorb(YoungGeneration youngGen) { } } + @Override + void appendChunk(AlignedHeapChunk.AlignedHeader hdr) { + space.appendAlignedHeapChunk(hdr); + } + @Override @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) void blackenDirtyCardRoots(GreyToBlackObjectVisitor visitor) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CopyingOldGeneration.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CopyingOldGeneration.java index 9962dff2e554..47e1cfe80779 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CopyingOldGeneration.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CopyingOldGeneration.java @@ -143,6 +143,11 @@ Space getToSpace() { return toSpace; } + @Override + void appendChunk(AlignedHeapChunk.AlignedHeader hdr) { + getToSpace().appendAlignedHeapChunk(hdr); + } + @Override void swapSpaces() { assert getFromSpace().isEmpty() : "fromSpace should be empty."; diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java index c72ca246ec6e..553affddaca4 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java @@ -28,6 +28,7 @@ import java.util.ArrayList; import java.util.List; +import com.oracle.svm.core.hub.LayoutEncoding; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.Platform; @@ -54,6 +55,7 @@ import com.oracle.svm.core.genscavenge.ThreadLocalAllocation.Descriptor; import com.oracle.svm.core.genscavenge.UnalignedHeapChunk.UnalignedHeader; import com.oracle.svm.core.genscavenge.graal.ForcedSerialPostWriteBarrier; +import com.oracle.svm.core.genscavenge.graal.nodes.FormatArrayNode; import com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets; import com.oracle.svm.core.heap.GC; import com.oracle.svm.core.heap.GCCause; @@ -66,6 +68,7 @@ import com.oracle.svm.core.heap.ReferenceInternals; import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.heap.RuntimeCodeInfoGCSupport; +import com.oracle.svm.core.heap.VMOperationInfos; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.jdk.UninterruptibleUtils.AtomicReference; @@ -80,6 +83,7 @@ import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.os.ImageHeapProvider; import com.oracle.svm.core.snippets.KnownIntrinsics; +import com.oracle.svm.core.thread.JavaVMOperation; import com.oracle.svm.core.thread.PlatformThreads; import com.oracle.svm.core.thread.ThreadStatus; import com.oracle.svm.core.thread.VMOperation; @@ -95,6 +99,7 @@ import jdk.graal.compiler.core.common.SuppressFBWarnings; import jdk.graal.compiler.nodes.extended.MembarNode; import jdk.graal.compiler.nodes.memory.address.OffsetAddressNode; +import jdk.graal.compiler.replacements.AllocationSnippets; import jdk.graal.compiler.word.Word; public final class HeapImpl extends Heap { @@ -111,6 +116,8 @@ public final class HeapImpl extends Heap { private final RuntimeCodeInfoGCSupportImpl runtimeCodeInfoGcSupport; private final HeapAccounting accounting = new HeapAccounting(); + private AlignedHeader lastDynamicHubChunk; + /** Head of the linked list of currently pending (ready to be enqueued) {@link Reference}s. */ private Reference refPendingList; /** Total number of times when a new pending reference list became available. */ @@ -933,6 +940,83 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev log.indent(false); } } + + public static DynamicHub allocateDynamicHub(int vTableSlots) { + AllocateDynamicHubOp vmOp = new AllocateDynamicHubOp(vTableSlots); + vmOp.enqueue(); + return vmOp.result; + } + + private static class AllocateDynamicHubOp extends JavaVMOperation { + int vTableSlots; + DynamicHub result; + + AllocateDynamicHubOp(int vTableSlots) { + super(VMOperationInfos.get(AllocateDynamicHubOp.class, "Allocate DynamicHub", SystemEffect.SAFEPOINT)); + this.vTableSlots = vTableSlots; + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public boolean isGC() { + /* needs to append chunks into oldGen */ + return true; + } + + @Override + protected void operate() { + DynamicHub hubOfDynamicHub = DynamicHub.fromClass(Class.class); + /* + * Note that layoutEncoding already encodes the size of a DynamicHub and it is aware of + * its hybrid nature, including the size required for a VTable slot. + * + * Also note that inlined fields like `closedTypeWorldTypeCheckSlots` are not relevant + * here, as they are not available in the open type world configuration. + */ + UnsignedWord size = LayoutEncoding.getArrayAllocationSize(hubOfDynamicHub.getLayoutEncoding(), vTableSlots); + + Pointer memory = WordFactory.nullPointer(); + if (getHeapImpl().lastDynamicHubChunk.isNonNull()) { + /* + * GR-57355: move this fast-path out of vmOp. Needs some locking (it's not + * thread-local) + */ + memory = AlignedHeapChunk.allocateMemory(getHeapImpl().lastDynamicHubChunk, size); + } + + if (memory.isNull()) { + /* Either no storage for DynamicHubs yet or we are out of memory */ + allocateNewDynamicHubChunk(); + + memory = AlignedHeapChunk.allocateMemory(getHeapImpl().lastDynamicHubChunk, size); + } + + VMError.guarantee(memory.isNonNull(), "failed to allocate DynamicHub"); + + /* DynamicHubs live allocated on aligned heap chunks */ + boolean unaligned = false; + result = (DynamicHub) FormatArrayNode.formatArray(memory, DynamicHub.class, vTableSlots, true, unaligned, AllocationSnippets.FillContent.WITH_ZEROES, true); + } + + private static void allocateNewDynamicHubChunk() { + /* + * GR-60085: Should be a dedicated generation. Make sure that those chunks are close to + * the heap base. The hub is stored as offset relative to the heap base. There are 5 + * status bits in the header and in addition, compressed references use a three-bit + * shift that word-aligns objects. This results in a 35-bit address range of 32 GB, of + * which DynamicHubs must reside in the lowest 1 GB. + */ + OldGeneration oldGeneration = getHeapImpl().getOldGeneration(); + + /* + * GR-60085: DynamicHub objects must never be be moved. Pin them either by (1) pinning + * each DynamicHub, or (2) mark the whole chunk as pinned (not supported yet). + */ + getHeapImpl().lastDynamicHubChunk = oldGeneration.requestAlignedChunk(); + + oldGeneration.appendChunk(getHeapImpl().lastDynamicHubChunk); + } + } } @TargetClass(value = java.lang.Runtime.class, onlyWith = UseSerialOrEpsilonGC.class) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/OldGeneration.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/OldGeneration.java index 22c43d93962a..f31a461a6059 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/OldGeneration.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/OldGeneration.java @@ -63,6 +63,8 @@ public abstract class OldGeneration extends Generation { abstract boolean isInSpace(Pointer ptr); + abstract void appendChunk(AlignedHeapChunk.AlignedHeader hdr); + abstract boolean verifyRememberedSets(); abstract boolean verifySpaces(); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java index 2dc00e124ef0..e22fa32b32a0 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java @@ -266,6 +266,11 @@ private static Object slowPathNewPodInstance(Word objectHeader, int arrayLength, return slowPathNewArrayLikeObject(objectHeader, arrayLength, referenceMap); } + @SubstrateForeignCallTarget(stubCallingConvention = false) + private static Object newDynamicHub(int vTableSlots) { + return HeapImpl.allocateDynamicHub(vTableSlots); + } + private static Object slowPathNewArrayLikeObject(Word objectHeader, int length, byte[] podReferenceMap) { /* * Avoid stack overflow errors while producing memory chunks, because that could leave the diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeAllocationSupport.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeAllocationSupport.java index cc3e14ed6296..a90ab31bb8dc 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeAllocationSupport.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeAllocationSupport.java @@ -33,6 +33,7 @@ import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; import com.oracle.svm.core.graal.snippets.GCAllocationSupport; import com.oracle.svm.core.heap.Pod; +import com.oracle.svm.core.hub.RuntimeClassLoading; import com.oracle.svm.core.snippets.SnippetRuntime; import com.oracle.svm.core.snippets.SnippetRuntime.SubstrateForeignCallDescriptor; import com.oracle.svm.core.thread.ContinuationSupport; @@ -45,6 +46,7 @@ public class GenScavengeAllocationSupport implements GCAllocationSupport { private static final SubstrateForeignCallDescriptor SLOW_NEW_ARRAY = SnippetRuntime.findForeignCall(ThreadLocalAllocation.class, "slowPathNewArray", NO_SIDE_EFFECT); private static final SubstrateForeignCallDescriptor SLOW_NEW_STORED_CONTINUATION = SnippetRuntime.findForeignCall(ThreadLocalAllocation.class, "slowPathNewStoredContinuation", NO_SIDE_EFFECT); private static final SubstrateForeignCallDescriptor SLOW_NEW_POD_INSTANCE = SnippetRuntime.findForeignCall(ThreadLocalAllocation.class, "slowPathNewPodInstance", NO_SIDE_EFFECT); + private static final SubstrateForeignCallDescriptor NEW_DYNAMICHUB = SnippetRuntime.findForeignCall(ThreadLocalAllocation.class, "newDynamicHub", NO_SIDE_EFFECT); private static final SubstrateForeignCallDescriptor[] UNCONDITIONAL_FOREIGN_CALLS = new SubstrateForeignCallDescriptor[]{SLOW_NEW_INSTANCE, SLOW_NEW_ARRAY}; public static void registerForeignCalls(SubstrateForeignCallsProvider foreignCalls) { @@ -55,6 +57,9 @@ public static void registerForeignCalls(SubstrateForeignCallsProvider foreignCal if (Pod.RuntimeSupport.isPresent()) { foreignCalls.register(SLOW_NEW_POD_INSTANCE); } + if (RuntimeClassLoading.isSupported()) { + foreignCalls.register(NEW_DYNAMICHUB); + } } @Override @@ -77,6 +82,11 @@ public ForeignCallDescriptor getNewPodInstanceStub() { return SLOW_NEW_POD_INSTANCE; } + @Override + public SubstrateForeignCallDescriptor getNewDynamicHub() { + return NEW_DYNAMICHUB; + } + @Override public boolean useTLAB() { return true; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/classinitialization/ClassInitializationInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/classinitialization/ClassInitializationInfo.java index 1f1c1338f952..07a1f10c4655 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/classinitialization/ClassInitializationInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/classinitialization/ClassInitializationInfo.java @@ -27,6 +27,7 @@ import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; +import com.oracle.svm.core.hub.RuntimeClassLoading; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.Platform; @@ -232,6 +233,19 @@ public ClassInitializationInfo(CFunctionPointer classInitializer, boolean typeRe this.hasInitializer = classInitializer != null; } + public ClassInitializationInfo(boolean typeReachedTracked) { + assert RuntimeClassLoading.isSupported(); + + this.classInitializer = null; + this.hasInitializer = true; + + // GR-59739: Needs a new state "Loaded". + this.initState = InitState.Linked; + this.typeReached = typeReachedTracked ? TypeReached.NOT_REACHED : TypeReached.UNTRACKED; + this.slowPathRequired = true; + this.initLock = new ReentrantLock(); + } + public boolean hasInitializer() { return hasInitializer; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/DynamicHubOffsets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/DynamicHubOffsets.java new file mode 100644 index 000000000000..479b6c8b41b9 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/DynamicHubOffsets.java @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2024, 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 + * 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. + */ +package com.oracle.svm.core.graal.meta; + +import java.lang.reflect.Field; +import java.util.Arrays; + +import jdk.graal.compiler.word.BarrieredAccess; +import org.graalvm.nativeimage.AnnotationAccess; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.BuildPhaseProvider; +import com.oracle.svm.core.annotate.InjectAccessors; +import com.oracle.svm.core.heap.UnknownPrimitiveField; +import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.util.ReflectionUtil; + +import jdk.graal.compiler.api.replacements.Fold; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; + +public class DynamicHubOffsets { + /* defining order in DynamicHub */ + + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int nameOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int hubTypeOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int referenceTypeOffset; + + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int layoutEncodingOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int typeIDOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int typeIDDepthOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int numClassTypesOffset; + + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int numInterfaceTypesOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int openTypeWorldTypeCheckSlotsOffset; + + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int monitorOffsetOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int identityHashOffsetOffset; + + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int flagsOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int additionalFlagsOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int modifiersOffset; + + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int superHubOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int componentTypeOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int arrayHubOffset; + + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int declaringClassOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int interfacesEncodingOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int enumConstantsReferenceOffset; + + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int referenceMapIndexOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int layerIdOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int metaTypeOffset; + + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int sourceFileNameOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int classInitializationInfoOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int moduleOffset; + + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int nestHostOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int simpleBinaryNameOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int companionOffset; + + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int signatureOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int classRedefinedCountOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int hubMetadataOffset; + @UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) // + private int reflectionMetadataOffset; + + @Fold + public static DynamicHubOffsets singleton() { + return ImageSingletons.lookup(DynamicHubOffsets.class); + } + + private static final String[] SKIPPED_FIELDS = new String[]{ + /* closed world only */ + "typeCheckStart", "typeCheckRange", "typeCheckSlot", "closedTypeWorldTypeCheckSlots", + + /* handled by KnownOffsets */ + "vtable" + }; + + @Platforms(Platform.HOSTED_ONLY.class) + public void initializeOffsets(MetaAccessProvider metaAccess) { + for (ResolvedJavaField field : metaAccess.lookupJavaType(DynamicHub.class).getInstanceFields(true)) { + if (Arrays.stream(SKIPPED_FIELDS).anyMatch(field.getName()::equals)) { + continue; + } + + if (AnnotationAccess.isAnnotationPresent(field, InjectAccessors.class)) { + continue; + } + + try { + Field offsetField = ReflectionUtil.lookupField(DynamicHubOffsets.class, field.getName() + "Offset"); + offsetField.setInt(singleton(), field.getOffset()); + } catch (IllegalAccessException e) { + throw VMError.shouldNotReachHere(e); + } + } + } + + public int getNameOffset() { + return nameOffset; + } + + public int getHubTypeOffset() { + return hubTypeOffset; + } + + public int getReferenceTypeOffset() { + return referenceTypeOffset; + } + + public int getLayoutEncodingOffset() { + return layoutEncodingOffset; + } + + public int getTypeIDOffset() { + return typeIDOffset; + } + + public int getTypeIDDepthOffset() { + return typeIDDepthOffset; + } + + public int getNumClassTypesOffset() { + return numClassTypesOffset; + } + + public int getNumInterfaceTypesOffset() { + return numInterfaceTypesOffset; + } + + public int getOpenTypeWorldTypeCheckSlotsOffset() { + return openTypeWorldTypeCheckSlotsOffset; + } + + public int getMonitorOffsetOffset() { + return monitorOffsetOffset; + } + + public int getIdentityHashOffsetOffset() { + return identityHashOffsetOffset; + } + + public int getFlagsOffset() { + return flagsOffset; + } + + public int getAdditionalFlagsOffset() { + return additionalFlagsOffset; + } + + public int getModifiersOffset() { + return modifiersOffset; + } + + public int getSuperHubOffset() { + return superHubOffset; + } + + public int getComponentTypeOffset() { + return componentTypeOffset; + } + + public int getArrayHubOffset() { + return arrayHubOffset; + } + + public int getDeclaringClassOffset() { + return declaringClassOffset; + } + + public int getInterfacesEncodingOffset() { + return interfacesEncodingOffset; + } + + public int getEnumConstantsReferenceOffset() { + return enumConstantsReferenceOffset; + } + + public int getReferenceMapIndexOffset() { + return referenceMapIndexOffset; + } + + public int getLayerIdOffset() { + return layerIdOffset; + } + + public int getMetaTypeOffset() { + return metaTypeOffset; + } + + public int getSourceFileNameOffset() { + return sourceFileNameOffset; + } + + public int getClassInitializationInfoOffset() { + return classInitializationInfoOffset; + } + + public int getModuleOffset() { + return moduleOffset; + } + + public int getNestHostOffset() { + return nestHostOffset; + } + + public int getSimpleBinaryNameOffset() { + return simpleBinaryNameOffset; + } + + public int getCompanionOffset() { + return companionOffset; + } + + public int getSignatureOffset() { + return signatureOffset; + } + + public int getClassRedefinedCountOffset() { + return classRedefinedCountOffset; + } + + public int getHubMetadataOffset() { + return hubMetadataOffset; + } + + public int getReflectionMetadataOffset() { + return reflectionMetadataOffset; + } + + public static void writeObject(DynamicHub hub, int offset, Object value) { + if (offset < 0) { + /* field removed by analysis */ + return; + } + BarrieredAccess.writeObject(hub, offset, value); + } + + public static void writeInt(DynamicHub hub, int offset, int value) { + if (offset < 0) { + /* field removed by analysis */ + return; + } + BarrieredAccess.writeInt(hub, offset, value); + } + + public static void writeShort(DynamicHub hub, int offset, short value) { + if (offset < 0) { + /* field removed by analysis */ + return; + } + BarrieredAccess.writeShort(hub, offset, value); + } + + public static void writeChar(DynamicHub hub, int offset, char value) { + if (offset < 0) { + /* field removed by analysis */ + return; + } + BarrieredAccess.writeChar(hub, offset, value); + } + + public static void writeByte(DynamicHub hub, int offset, byte value) { + if (offset < 0) { + /* field removed by analysis */ + return; + } + BarrieredAccess.writeByte(hub, offset, value); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/KnownOffsets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/KnownOffsets.java index 77a2ddd5e4f6..3e1eed3ce325 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/KnownOffsets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/KnownOffsets.java @@ -53,8 +53,6 @@ public final class KnownOffsets { @UnknownPrimitiveField(availability = ReadyForCompilation.class) // private int typeIDSlotsOffset; @UnknownPrimitiveField(availability = ReadyForCompilation.class) // - private int componentHubOffset; - @UnknownPrimitiveField(availability = ReadyForCompilation.class) // private int javaFrameAnchorLastSPOffset; @UnknownPrimitiveField(availability = ReadyForCompilation.class) // private int javaFrameAnchorLastIPOffset; @@ -69,14 +67,15 @@ public static KnownOffsets singleton() { } @Platforms(Platform.HOSTED_ONLY.class) - public void setLazyState(int vtableBaseOffset, int vtableEntrySize, int typeIDSlotsOffset, int componentHubOffset, - int javaFrameAnchorLastSPOffset, int javaFrameAnchorLastIPOffset, int vmThreadStatusOffset, int imageCodeInfoCodeStartOffset) { + public void setLazyState(int vtableBaseOffset, int vtableEntrySize, int typeIDSlotsOffset, + int javaFrameAnchorLastSPOffset, int javaFrameAnchorLastIPOffset, + int vmThreadStatusOffset, int imageCodeInfoCodeStartOffset) { assert !isFullyInitialized(); this.vtableBaseOffset = vtableBaseOffset; this.vtableEntrySize = vtableEntrySize; this.typeIDSlotsOffset = typeIDSlotsOffset; - this.componentHubOffset = componentHubOffset; + this.javaFrameAnchorLastSPOffset = javaFrameAnchorLastSPOffset; this.javaFrameAnchorLastIPOffset = javaFrameAnchorLastIPOffset; this.vmThreadStatusOffset = vmThreadStatusOffset; @@ -89,7 +88,7 @@ public void setLazyState(int vtableBaseOffset, int vtableEntrySize, int typeIDSl vtableBaseOffset, vtableEntrySize, typeIDSlotsOffset, - componentHubOffset, + javaFrameAnchorLastSPOffset, javaFrameAnchorLastIPOffset, vmThreadStatusOffset, @@ -137,11 +136,6 @@ public int getTypeIDSlotsOffset() { return typeIDSlotsOffset; } - public int getComponentHubOffset() { - assert isFullyInitialized(); - return componentHubOffset; - } - public int getJavaFrameAnchorLastSPOffset() { assert isFullyInitialized(); return javaFrameAnchorLastSPOffset; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java index 598fbc3f6e2e..2b90c7c45471 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java @@ -102,6 +102,7 @@ public abstract class SubstrateBasicLoweringProvider extends DefaultJavaLowering private RuntimeConfiguration runtimeConfig; private final KnownOffsets knownOffsets; + private final DynamicHubOffsets dynamicHubOffsets; private final AbstractObjectStamp hubStamp; @Platforms(Platform.HOSTED_ONLY.class) @@ -117,6 +118,7 @@ public SubstrateBasicLoweringProvider(MetaAccessProvider metaAccess, ForeignCall } hubStamp = hubRefStamp; knownOffsets = KnownOffsets.singleton(); + dynamicHubOffsets = DynamicHubOffsets.singleton(); } @Override @@ -220,7 +222,7 @@ private static ValueNode maybeUncompress(ValueNode node) { @Override protected ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, boolean isKnownObjectArray, FixedNode anchor) { - ConstantNode componentHubOffset = ConstantNode.forIntegerKind(target.wordJavaKind, knownOffsets.getComponentHubOffset(), graph); + ConstantNode componentHubOffset = ConstantNode.forIntegerKind(target.wordJavaKind, dynamicHubOffsets.getComponentTypeOffset(), graph); AddressNode componentHubAddress = graph.unique(new OffsetAddressNode(arrayHub, componentHubOffset)); FloatingReadNode componentHubRef = graph.unique(new FloatingReadNode(componentHubAddress, NamedLocationIdentity.FINAL_LOCATION, null, hubStamp, null, BarrierType.NONE)); return maybeUncompress(componentHubRef); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/SubstrateNewDynamicHubNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/SubstrateNewDynamicHubNode.java new file mode 100644 index 000000000000..28b7a4aabff4 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/SubstrateNewDynamicHubNode.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024, 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 + * 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. + */ +package com.oracle.svm.core.graal.nodes; + +import com.oracle.svm.core.hub.DynamicHub; +import jdk.graal.compiler.core.common.type.StampFactory; +import jdk.graal.compiler.core.common.type.TypeReference; +import jdk.graal.compiler.graph.NodeClass; +import jdk.graal.compiler.nodeinfo.NodeInfo; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.java.AbstractNewObjectNode; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * The {@link SubstrateNewDynamicHubNode} represents the allocation of a new + * {@link com.oracle.svm.core.hub.DynamicHub} at execution time. + */ +@NodeInfo(nameTemplate = "SubstrateNewDynamicHubNode") +public final class SubstrateNewDynamicHubNode extends AbstractNewObjectNode { + public static final NodeClass TYPE = NodeClass.create(SubstrateNewDynamicHubNode.class); + + @Input ValueNode vTableEntries; + + public SubstrateNewDynamicHubNode(ResolvedJavaType dynamicHubType, ValueNode vTableEntries) { + super(TYPE, StampFactory.objectNonNull(TypeReference.createExactTrusted(dynamicHubType)), true, null); + this.vTableEntries = vTableEntries; + } + + public ValueNode getVTableEntries() { + return vTableEntries; + } + + @NodeIntrinsic + public static native DynamicHub allocate(@ConstantNodeParameter Class dynamicHubType, int vTableEntries); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/GCAllocationSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/GCAllocationSupport.java index f8a091d2aed2..6ba29e4f40ea 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/GCAllocationSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/GCAllocationSupport.java @@ -41,6 +41,8 @@ public interface GCAllocationSupport { ForeignCallDescriptor getNewPodInstanceStub(); + ForeignCallDescriptor getNewDynamicHub(); + boolean useTLAB(); boolean shouldAllocateInTLAB(UnsignedWord size, boolean isArray); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java index 7de4fe5f89fc..c8f676cf2a4a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java @@ -36,6 +36,8 @@ import java.util.Arrays; import java.util.Map; +import com.oracle.svm.core.graal.meta.KnownOffsets; +import jdk.graal.compiler.core.common.NumUtil; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.word.LocationIdentity; import org.graalvm.word.UnsignedWord; @@ -50,11 +52,13 @@ import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; import com.oracle.svm.core.graal.nodes.NewPodInstanceNode; import com.oracle.svm.core.graal.nodes.NewStoredContinuationNode; +import com.oracle.svm.core.graal.nodes.SubstrateNewDynamicHubNode; import com.oracle.svm.core.graal.nodes.SubstrateNewHybridInstanceNode; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.Pod; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.LayoutEncoding; +import com.oracle.svm.core.hub.RuntimeClassLoading; import com.oracle.svm.core.identityhashcode.IdentityHashCodeSupport; import com.oracle.svm.core.meta.SharedType; import com.oracle.svm.core.option.HostedOptionValues; @@ -227,6 +231,22 @@ public Object allocatePod(@NonNullParameter DynamicHub hub, return piArrayCastToSnippetReplaceeStamp(verifyOop(result), arrayLength); } + @Snippet + public Object allocateDynamicHub(int vTableEntries, + @ConstantParameter int vTableBaseOffset, + @ConstantParameter int log2VTableEntrySize, + @ConstantParameter AllocationProfilingData profilingData) { + profilingData.snippetCounters.stub.inc(); + + // always slow path, because DynamicHubs are allocated into dedicated chunks + Object result = callNewDynamicHub(gcAllocationSupport().getNewDynamicHub(), vTableEntries); + + UnsignedWord allocationSize = arrayAllocationSize(vTableEntries, vTableBaseOffset, log2VTableEntrySize); + profileAllocation(profilingData, allocationSize); + + return piArrayCastToSnippetReplaceeStamp(verifyOop(result), vTableEntries); + } + @Snippet public Object allocateInstanceDynamic(@NonNullParameter DynamicHub hub, @ConstantParameter boolean forceSlowPath, @@ -521,6 +541,9 @@ protected final Object callNewMultiArrayStub(Word objectHeader, int rank, Word d @NodeIntrinsic(value = ForeignCallNode.class) private static native Object callSlowNewStoredContinuation(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word hub, int length); + @NodeIntrinsic(value = ForeignCallNode.class) + private static native Object callNewDynamicHub(@ConstantNodeParameter ForeignCallDescriptor descriptor, int vTableEntries); + @NodeIntrinsic(value = ForeignCallNode.class) private static native Object callNewMultiArray(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word hub, int rank, Word dimensions); @@ -591,6 +614,7 @@ public static class Templates extends SubstrateTemplates { private final SnippetInfo allocateStoredContinuation; private final SnippetInfo allocatePod; + private final SnippetInfo allocateDynamicHub; @SuppressWarnings("this-escape") public Templates(OptionValues options, Providers providers, SubstrateAllocationSnippets receiver) { @@ -659,6 +683,17 @@ public Templates(OptionValues options, Providers providers, SubstrateAllocationS podLocations); } allocatePod = allocatePodSnippet; + + SnippetInfo allocateDynamicHubSnippet = null; + if (RuntimeClassLoading.isSupported()) { + allocateDynamicHubSnippet = snippet(providers, + SubstrateAllocationSnippets.class, + "allocateDynamicHub", + null, + receiver, + ALLOCATION_LOCATIONS); + } + allocateDynamicHub = allocateDynamicHubSnippet; } public void registerLowering(Map, NodeLoweringProvider> lowerings) { @@ -687,6 +722,9 @@ public void registerLowering(Map, NodeLoweringProvider> if (Pod.RuntimeSupport.isPresent()) { lowerings.put(NewPodInstanceNode.class, new NewPodInstanceLowering()); } + if (RuntimeClassLoading.isSupported()) { + lowerings.put(SubstrateNewDynamicHubNode.class, new NewDynamicHubLowering()); + } } public AllocationSnippetCounters getSnippetCounters() { @@ -1097,6 +1135,39 @@ public void lower(NewPodInstanceNode node, LoweringTool tool) { template(tool, node, args).instantiate(tool.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args); } } + + private class NewDynamicHubLowering implements NodeLoweringProvider { + @Override + public void lower(SubstrateNewDynamicHubNode node, LoweringTool tool) { + StructuredGraph graph = node.graph(); + if (graph.getGuardsStage().areFrameStatesAtSideEffects()) { + return; + } + + assert node.getVTableEntries() != null; + assert node.fillContents() : "fillContents must be true for DynamicHub allocations"; + + ValueNode vTableEntries = node.getVTableEntries(); + SharedType type = (SharedType) tool.getMetaAccess().lookupJavaType(Class.class); + DynamicHub hubOfDynamicHub = type.getHub(); + + int layoutEncoding = hubOfDynamicHub.getLayoutEncoding(); + + int vTableBaseOffset = getArrayBaseOffset(layoutEncoding); + assert vTableBaseOffset == KnownOffsets.singleton().getVTableBaseOffset(); + + int log2VTableEntrySize = LayoutEncoding.getArrayIndexShift(layoutEncoding); + assert log2VTableEntrySize == NumUtil.unsignedLog2(KnownOffsets.singleton().getVTableEntrySize()); + + Arguments args = new Arguments(allocateDynamicHub, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("vTableEntries", vTableEntries); + args.add("vTableBaseOffset", vTableBaseOffset); + args.add("log2VTableEntrySize", log2VTableEntrySize); + args.add("profilingData", getProfilingData(node, type)); + + template(tool, node, args).instantiate(tool.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args); + } + } } /** diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index 9d83bf6bd9ed..f329bf51111d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -40,6 +40,11 @@ import static com.oracle.svm.core.code.RuntimeMetadataDecoderImpl.ALL_RECORD_COMPONENTS_FLAG; import static com.oracle.svm.core.code.RuntimeMetadataDecoderImpl.ALL_SIGNERS_FLAG; import static com.oracle.svm.core.code.RuntimeMetadataDecoderImpl.CLASS_ACCESS_FLAGS_MASK; +import static com.oracle.svm.core.graal.meta.DynamicHubOffsets.writeObject; +import static com.oracle.svm.core.graal.meta.DynamicHubOffsets.writeInt; +import static com.oracle.svm.core.graal.meta.DynamicHubOffsets.writeChar; +import static com.oracle.svm.core.graal.meta.DynamicHubOffsets.writeShort; +import static com.oracle.svm.core.graal.meta.DynamicHubOffsets.writeByte; import static com.oracle.svm.core.reflect.RuntimeMetadataDecoder.NO_DATA; import java.io.InputStream; @@ -85,6 +90,7 @@ import com.oracle.svm.core.BuildPhaseProvider.AfterCompilation; import com.oracle.svm.core.BuildPhaseProvider.AfterHostedUniverse; import com.oracle.svm.core.BuildPhaseProvider.CompileQueueFinished; +import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.RuntimeAssertionsSupport; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.Uninterruptible; @@ -101,8 +107,11 @@ import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.config.ObjectLayout; import com.oracle.svm.core.configure.RuntimeConditionSet; +import com.oracle.svm.core.graal.meta.DynamicHubOffsets; +import com.oracle.svm.core.graal.nodes.SubstrateNewDynamicHubNode; import com.oracle.svm.core.heap.UnknownObjectField; import com.oracle.svm.core.heap.UnknownPrimitiveField; +import com.oracle.svm.core.imagelayer.DynamicImageLayerInfo; import com.oracle.svm.core.jdk.JDK21OrEarlier; import com.oracle.svm.core.jdk.JDKLatest; import com.oracle.svm.core.jdk.Resources; @@ -123,6 +132,7 @@ import jdk.graal.compiler.api.directives.GraalDirectives; import jdk.graal.compiler.core.common.NumUtil; import jdk.graal.compiler.core.common.SuppressFBWarnings; +import jdk.graal.compiler.nodes.java.FinalFieldBarrierNode; import jdk.graal.compiler.replacements.ReplacementsUtil; import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.internal.access.JavaLangReflectAccess; @@ -141,6 +151,10 @@ /** * Instantiations of this class have a special layout. See {@code DynamicHubLayout} for a * description of how the object is arranged. + *

+ * A {@code DynamicHub} ends up initialized in the read-only part of the image heap, and therefore + * fields are considered immutable. In scenarios where a {@code DynamicHub} can be allocated at + * run-time it is important to keep this property. */ @Substitute @TargetClass(java.lang.Class.class) @@ -384,6 +398,7 @@ public final class DynamicHub implements AnnotatedElement, java.lang.reflect.Typ * classes/interfaces already initialized during image generation, i.e., this field is never * null at run time. */ + @Stable // private ClassInitializationInfo classInitializationInfo; @UnknownObjectField(availability = AfterHostedUniverse.class)// @@ -430,17 +445,16 @@ public final class DynamicHub implements AnnotatedElement, java.lang.reflect.Typ @InjectAccessors(CachedConstructorAccessors.class) // private Constructor cachedConstructor; - @UnknownObjectField(canBeNull = true, availability = AfterCompilation.class) private DynamicHubMetadata hubMetadata; + @UnknownObjectField(canBeNull = true, availability = AfterCompilation.class) // + private DynamicHubMetadata hubMetadata; - @UnknownObjectField(canBeNull = true, availability = AfterCompilation.class) private ReflectionMetadata reflectionMetadata; + @UnknownObjectField(canBeNull = true, availability = AfterCompilation.class) // + private ReflectionMetadata reflectionMetadata; @Platforms(Platform.HOSTED_ONLY.class) - public DynamicHub(Class hostedJavaClass, String name, int hubType, ReferenceType referenceType, DynamicHub superType, DynamicHub componentHub, String sourceFileName, int modifiers, - ClassLoader classLoader, boolean isHidden, boolean isRecord, Class nestHost, boolean assertionStatus, boolean hasDefaultMethods, boolean declaresDefaultMethods, - boolean isSealed, boolean isVMInternal, boolean isLambdaFormHidden, boolean isLinked, String simpleBinaryName, Object declaringClass, String signature, boolean isProxyClass, - int layerId) { - VMError.guarantee(layerId == (byte) layerId, "Layer id %d not in expected range", layerId); - + public DynamicHub(Class hostedJavaClass, String name, int hubType, ReferenceType referenceType, DynamicHub superType, + DynamicHub componentHub, String sourceFileName, int modifiers, short flags, ClassLoader classLoader, + Class nestHost, String simpleBinaryName, Object declaringClass, String signature, int layerId) { this.hostedJavaClass = hostedJavaClass; this.module = hostedJavaClass.getModule(); this.name = name; @@ -454,10 +468,145 @@ public DynamicHub(Class hostedJavaClass, String name, int hubType, ReferenceT this.simpleBinaryName = simpleBinaryName; this.declaringClass = declaringClass; this.signature = signature; - this.layerId = (byte) layerId; - this.flags = NumUtil.safeToUShort(makeFlag(IS_PRIMITIVE_FLAG_BIT, hostedJavaClass.isPrimitive()) | - makeFlag(IS_INTERFACE_FLAG_BIT, hostedJavaClass.isInterface()) | + assert layerId < DynamicImageLayerInfo.CREMA_LAYER_ID; + this.layerId = NumUtil.safeToByte(layerId); + + this.flags = flags; + + this.companion = new DynamicHubCompanion(hostedJavaClass, classLoader); + } + + /** + * This helper is used for allocating and initializing a new {@code DynamicHub} at runtime. + *

+ * Fields in {@code DynamicHub} are immutable, and writes in this method have location identity + * {@code ANY_LOCATION}: With this setup the compiler is allowed to float reads above such + * writes, therefore there must not be any reads in this helper. Also, further code must not be + * reachable that reads from the just created {@code DynamicHub} in this method. + *

+ * Regular stores should also not be used for non-final fields of {@code DynamicHub}, otherwise + * the analysis won't conclude immutability for such fields. + *

+ * Note that the GC can handle partially initialized {@code DynamicHub}s therefore this helper + * does not need to be {@link Uninterruptible}. However, other components might not, e.g. a + * {@code DynamicHub} must be fully initialized when it is used in an object header. + */ + @NeverInline("Fields of DynamicHub are immutable. Immutable reads could float above ANY_LOCATION writes.") + public static DynamicHub allocate(String name, DynamicHub superHub, DynamicHub componentHub, String sourceFileName, + int modifiers, short flags, ClassLoader classLoader, Class nestHost, String simpleBinaryName, + Object declaringClass, String signature) { + VMError.guarantee(RuntimeClassLoading.isSupported()); + + ReferenceType referenceType = ReferenceType.computeReferenceType(DynamicHub.toClass(superHub)); + // GR-59683: HubType.OBJECT_ARRAY? + int hubTybe = referenceType == ReferenceType.None ? HubType.INSTANCE : HubType.REFERENCE_INSTANCE; + + DynamicHubCompanion companion = new DynamicHubCompanion(classLoader); + /* Always allow unsafe allocation for classes that were loaded at run-time. */ + companion.setUnsafeAllocate(); + + // GR-59687: Correct size and content for vtable + int vTableEntries = 0x100; + ClassInitializationInfo classInitializationInfo = new ClassInitializationInfo(false); + + // GR-60069: Determine size for instance and offsets for monitor and identityHashCode + int layoutEncoding = 0x40; + char monitorOffset = 0; + char identityHashOffset = 0; + + // GR-59687: Determine typecheck related infos + int typeID = 0; + int typeIDDepth = 0; + int numClassTypes = 2; + int numInterfacesTypes = 0; + int[] openTypeWorldTypeCheckSlots = new int[numClassTypes + (numInterfacesTypes * 2)]; + + byte additionalFlags = NumUtil.safeToUByte(makeFlag(IS_INSTANTIATED_BIT, true)); + + // GR-59683: Proper values needed. + DynamicHub arrayHub = null; + Object interfacesEncoding = null; + Object enumConstantsReference = null; + + // GR-60080: Proper referenceMap needed. + int referenceMapIndex = DynamicHub.fromClass(Object.class).referenceMapIndex; + + // GR-59683: Maybe can be used to inject a backreference to InterpreterResolvedObjectType + SharedType metaType = null; + + // GR-59683 + Module module = null; + + // GR-57813 + int classRedefinedCount = 0; + DynamicHubMetadata hubMetadata = null; + ReflectionMetadata reflectionMetadata = null; + + /* + * We cannot do the allocation via {@code new DynamicHub(...)} because we need to inject the + * length for its vtable. + */ + DynamicHub hub = SubstrateNewDynamicHubNode.allocate(DynamicHub.class, vTableEntries); + + DynamicHubOffsets dynamicHubOffsets = DynamicHubOffsets.singleton(); + /* Write fields in defining order. */ + writeObject(hub, dynamicHubOffsets.getNameOffset(), name); + writeInt(hub, dynamicHubOffsets.getHubTypeOffset(), hubTybe); + writeByte(hub, dynamicHubOffsets.getReferenceTypeOffset(), referenceType.getValue()); + + writeInt(hub, dynamicHubOffsets.getLayoutEncodingOffset(), layoutEncoding); + writeInt(hub, dynamicHubOffsets.getTypeIDOffset(), typeID); + // skip typeCheckStart, typeCheckRange, typeCheckSlot and + // closedTypeWorldTypeCheckSlots (closed-world only) + writeInt(hub, dynamicHubOffsets.getTypeIDDepthOffset(), typeIDDepth); + writeInt(hub, dynamicHubOffsets.getNumClassTypesOffset(), numClassTypes); + + writeInt(hub, dynamicHubOffsets.getNumInterfaceTypesOffset(), numInterfacesTypes); + writeObject(hub, dynamicHubOffsets.getOpenTypeWorldTypeCheckSlotsOffset(), openTypeWorldTypeCheckSlots); + + writeChar(hub, dynamicHubOffsets.getMonitorOffsetOffset(), monitorOffset); + writeChar(hub, dynamicHubOffsets.getIdentityHashOffsetOffset(), identityHashOffset); + + writeShort(hub, dynamicHubOffsets.getFlagsOffset(), flags); + writeByte(hub, dynamicHubOffsets.getAdditionalFlagsOffset(), additionalFlags); + writeInt(hub, dynamicHubOffsets.getModifiersOffset(), modifiers); + + writeObject(hub, dynamicHubOffsets.getSuperHubOffset(), superHub); + writeObject(hub, dynamicHubOffsets.getComponentTypeOffset(), componentHub); + writeObject(hub, dynamicHubOffsets.getArrayHubOffset(), arrayHub); + + writeObject(hub, dynamicHubOffsets.getDeclaringClassOffset(), declaringClass); + writeObject(hub, dynamicHubOffsets.getInterfacesEncodingOffset(), interfacesEncoding); + writeObject(hub, dynamicHubOffsets.getEnumConstantsReferenceOffset(), enumConstantsReference); + + writeInt(hub, dynamicHubOffsets.getReferenceMapIndexOffset(), referenceMapIndex); + writeByte(hub, dynamicHubOffsets.getLayerIdOffset(), NumUtil.safeToByte(DynamicImageLayerInfo.CREMA_LAYER_ID)); + writeObject(hub, dynamicHubOffsets.getMetaTypeOffset(), metaType); + + writeObject(hub, dynamicHubOffsets.getSourceFileNameOffset(), sourceFileName); + writeObject(hub, dynamicHubOffsets.getClassInitializationInfoOffset(), classInitializationInfo); + // skip vtable (special treatment) + writeObject(hub, dynamicHubOffsets.getModuleOffset(), module); + + writeObject(hub, dynamicHubOffsets.getNestHostOffset(), nestHost); + writeObject(hub, dynamicHubOffsets.getSimpleBinaryNameOffset(), simpleBinaryName); + writeObject(hub, dynamicHubOffsets.getCompanionOffset(), companion); + + writeObject(hub, dynamicHubOffsets.getSignatureOffset(), signature); + writeInt(hub, dynamicHubOffsets.getClassRedefinedCountOffset(), classRedefinedCount); + writeObject(hub, dynamicHubOffsets.getHubMetadataOffset(), hubMetadata); + writeObject(hub, dynamicHubOffsets.getReflectionMetadataOffset(), reflectionMetadata); + + FinalFieldBarrierNode.finalFieldBarrier(hub); + + return hub; + } + + public static short makeFlags(boolean isPrimitive, boolean isInterface, boolean isHidden, boolean isRecord, boolean assertionStatus, boolean hasDefaultMethods, boolean declaresDefaultMethods, + boolean isSealed, boolean isVMInternal, boolean isLambdaFormHidden, boolean isLinked, boolean isProxyClass) { + return NumUtil.safeToUShort(makeFlag(IS_PRIMITIVE_FLAG_BIT, isPrimitive) | + makeFlag(IS_INTERFACE_FLAG_BIT, isInterface) | makeFlag(IS_HIDDEN_FLAG_BIT, isHidden) | makeFlag(IS_RECORD_FLAG_BIT, isRecord) | makeFlag(ASSERTION_STATUS_FLAG_BIT, assertionStatus) | @@ -468,11 +617,8 @@ public DynamicHub(Class hostedJavaClass, String name, int hubType, ReferenceT makeFlag(IS_LAMBDA_FORM_HIDDEN_BIT, isLambdaFormHidden) | makeFlag(IS_LINKED_BIT, isLinked) | makeFlag(IS_PROXY_CLASS_BIT, isProxyClass)); - - this.companion = new DynamicHubCompanion(hostedJavaClass, classLoader); } - @Platforms(Platform.HOSTED_ONLY.class) private static int makeFlag(int flagBit, boolean value) { int flagMask = 1 << flagBit; return value ? flagMask : 0; @@ -492,6 +638,7 @@ private static boolean isFlagSet(short flags, int flagBit) { @Platforms(Platform.HOSTED_ONLY.class) public void setClassInitializationInfo(ClassInitializationInfo classInitializationInfo) { + assert classInitializationInfo != null; this.classInitializationInfo = classInitializationInfo; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHubCompanion.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHubCompanion.java index d3748d52e5c6..16f94b255765 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHubCompanion.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHubCompanion.java @@ -66,6 +66,11 @@ public final class DynamicHubCompanion { this.classLoader = PredefinedClassesSupport.isPredefined(hostedJavaClass) ? NO_CLASS_LOADER : classLoader; } + DynamicHubCompanion(ClassLoader classLoader) { + assert RuntimeClassLoading.isSupported(); + this.classLoader = classLoader; + } + String getPackageName(DynamicHub hub) { if (packageName == null) { packageName = hub.computePackageName(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ReferenceType.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ReferenceType.java index 9bf1c10b44ea..7a23e9e5c478 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ReferenceType.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ReferenceType.java @@ -24,10 +24,14 @@ */ package com.oracle.svm.core.hub; -import jdk.graal.compiler.core.common.NumUtil; +import java.lang.ref.PhantomReference; +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; import com.oracle.svm.core.util.DuplicatedInNativeCode; +import jdk.graal.compiler.core.common.NumUtil; + @DuplicatedInNativeCode public enum ReferenceType { None(0), // non-reference class @@ -45,4 +49,18 @@ public enum ReferenceType { public byte getValue() { return value; } + + public static ReferenceType computeReferenceType(Class type) { + if (Reference.class.isAssignableFrom(type)) { + if (PhantomReference.class.isAssignableFrom(type)) { + return ReferenceType.Phantom; + } else if (SoftReference.class.isAssignableFrom(type)) { + return ReferenceType.Soft; + } else { + /* Treat all other java.lang.Reference subclasses as weak references. */ + return ReferenceType.Weak; + } + } + return ReferenceType.None; + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeClassLoadingSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeClassLoading.java similarity index 77% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeClassLoadingSupport.java rename to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeClassLoading.java index 2596e2d4fef0..4b62bdb17c66 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeClassLoadingSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeClassLoading.java @@ -24,6 +24,10 @@ */ package com.oracle.svm.core.hub; +import static jdk.graal.compiler.options.OptionStability.EXPERIMENTAL; + +import org.graalvm.collections.EconomicMap; + import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.option.SubstrateOptionsParser; @@ -31,11 +35,22 @@ import jdk.graal.compiler.api.replacements.Fold; import jdk.graal.compiler.options.Option; +import jdk.graal.compiler.options.OptionKey; -public class RuntimeClassLoadingSupport { +public class RuntimeClassLoading { public static final class Options { - @Option(help = "Enable support for runtime class loading.") // - public static final HostedOptionKey SupportRuntimeClassLoading = new HostedOptionKey<>(false, Options::validate); + @Option(help = "Enable support for runtime class loading.", stability = EXPERIMENTAL) // + public static final HostedOptionKey SupportRuntimeClassLoading = new HostedOptionKey<>(false, Options::validate) { + + @Override + protected void onValueUpdate(EconomicMap, Object> values, Boolean oldValue, Boolean newValue) { + super.onValueUpdate(values, oldValue, newValue); + if (newValue) { + /* requires open type world */ + SubstrateOptions.ClosedTypeWorld.update(values, false); + } + } + }; private static void validate(HostedOptionKey optionKey) { if (optionKey.hasBeenSet() && optionKey.getValue() && SubstrateOptions.ClosedTypeWorld.getValue()) { @@ -45,10 +60,8 @@ private static void validate(HostedOptionKey optionKey) { } } - public static final String ENABLE_CLASS_LOADING_OPTION = SubstrateOptionsParser.commandArgument(Options.SupportRuntimeClassLoading, "+"); - @Fold - public static boolean supportsRuntimeClassLoading() { + public static boolean isSupported() { return Options.SupportRuntimeClassLoading.getValue(); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/DynamicImageLayerInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/DynamicImageLayerInfo.java index c09d1665b895..f6dc62618f11 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/DynamicImageLayerInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/DynamicImageLayerInfo.java @@ -30,6 +30,8 @@ import com.oracle.svm.core.meta.SharedMethod; public abstract class DynamicImageLayerInfo { + public static final int CREMA_LAYER_ID = Byte.MAX_VALUE; + public final int layerNumber; public final int nextLayerNumber; public final int numLayers; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java index eb76759a767f..ca93e9d93755 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java @@ -45,7 +45,8 @@ import com.oracle.svm.core.annotate.TargetElement; import com.oracle.svm.core.hub.ClassForNameSupport; import com.oracle.svm.core.hub.PredefinedClassesSupport; -import com.oracle.svm.core.hub.RuntimeClassLoadingSupport; +import com.oracle.svm.core.hub.RuntimeClassLoading; +import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.util.VMError; import jdk.graal.compiler.java.LambdaUtils; @@ -275,7 +276,7 @@ private Class defineClass(String name, byte[] b, int off, int len, Protection @SuppressWarnings({"unused", "static-method"}) private Class defineClass(String name, java.nio.ByteBuffer b, ProtectionDomain protectionDomain) { // only bother extracting the bytes if it has a chance to work - if (PredefinedClassesSupport.hasBytecodeClasses() || RuntimeClassLoadingSupport.supportsRuntimeClassLoading()) { + if (PredefinedClassesSupport.hasBytecodeClasses() || RuntimeClassLoading.isSupported()) { byte[] array; int off; int len = b.remaining(); @@ -323,11 +324,13 @@ private static Class defineClass0(ClassLoader loader, Class lookup, String } final class ClassLoaderHelper { + private static final String ERROR_MSG = SubstrateOptionsParser.commandArgument(RuntimeClassLoading.Options.SupportRuntimeClassLoading, "+") + " is not yet supported."; + public static Class defineClass(ClassLoader loader, String name, byte[] b, int off, int len, ProtectionDomain protectionDomain) { if (PredefinedClassesSupport.hasBytecodeClasses()) { return PredefinedClassesSupport.loadClass(loader, name, b, off, len, protectionDomain); } - throw VMError.unimplemented("Crema"); + throw VMError.unimplemented(ERROR_MSG); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 796b8d6e1928..89c9e5658ec1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -52,6 +52,7 @@ import java.util.function.BooleanSupplier; import java.util.function.Function; +import com.oracle.svm.hosted.substitute.DynamicHubPlugin; import org.graalvm.collections.EconomicSet; import org.graalvm.collections.Pair; import org.graalvm.nativeimage.ImageInfo; @@ -1379,6 +1380,7 @@ public static void registerGraphBuilderPlugins(FeatureHandler featureHandler, Ru plugins.appendNodePlugin(new ConstantFoldLoadFieldPlugin(reason)); plugins.appendNodePlugin(new CInterfaceInvocationPlugin(providers.getMetaAccess(), nativeLibs)); plugins.appendNodePlugin(new LocalizationFeature.CharsetNodePlugin()); + plugins.appendNodePlugin(new DynamicHubPlugin()); plugins.appendInlineInvokePlugin(wordOperationPlugin); plugins.appendTypePlugin(wordOperationPlugin); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index 6d9c11ff30c9..3752c2ae773e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -24,9 +24,7 @@ */ package com.oracle.svm.hosted; -import java.lang.ref.PhantomReference; import java.lang.ref.Reference; -import java.lang.ref.SoftReference; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -527,9 +525,13 @@ private DynamicHub createHub(AnalysisType type) { */ boolean isProxyClass = Proxy.isProxyClass(javaClass); - return new DynamicHub(javaClass, className, computeHubType(type), computeReferenceType(type), superHub, componentHub, sourceFileName, modifiers, hubClassLoader, - isHidden, isRecord, nestHost, assertionStatus, type.hasDefaultMethods(), type.declaresDefaultMethods(), isSealed, isVMInternal, isLambdaFormHidden, isLinked, simpleBinaryName, - getDeclaringClass(javaClass), getSignature(javaClass), isProxyClass, layerId); + short flags = DynamicHub.makeFlags(javaClass.isPrimitive(), javaClass.isInterface(), isHidden, isRecord, assertionStatus, + type.hasDefaultMethods(), type.declaresDefaultMethods(), isSealed, isVMInternal, + isLambdaFormHidden, isLinked, isProxyClass); + + return new DynamicHub(javaClass, className, computeHubType(type), ReferenceType.computeReferenceType(javaClass), + superHub, componentHub, sourceFileName, modifiers, flags, hubClassLoader, nestHost, + simpleBinaryName, getDeclaringClass(javaClass), getSignature(javaClass), layerId); } private static final Method getSignature = ReflectionUtil.lookupMethod(Class.class, "getGenericSignature0"); @@ -621,21 +623,6 @@ private static int computeHubType(AnalysisType type) { return HubType.OTHER; } - private static ReferenceType computeReferenceType(AnalysisType type) { - Class clazz = type.getJavaClass(); - if (Reference.class.isAssignableFrom(clazz)) { - if (PhantomReference.class.isAssignableFrom(clazz)) { - return ReferenceType.Phantom; - } else if (SoftReference.class.isAssignableFrom(clazz)) { - return ReferenceType.Soft; - } else { - /* Treat all other java.lang.Reference subclasses as weak references. */ - return ReferenceType.Weak; - } - } - return ReferenceType.None; - } - @Override public void checkType(ResolvedJavaType type, AnalysisUniverse universe) { Class originalClass = OriginalClassProvider.getJavaClass(type); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/DynamicHubOffsetsFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/DynamicHubOffsetsFeature.java new file mode 100644 index 000000000000..b244e4420365 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/DynamicHubOffsetsFeature.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024, 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 + * 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. + */ +package com.oracle.svm.hosted.meta; + +import org.graalvm.nativeimage.ImageSingletons; + +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.graal.meta.DynamicHubOffsets; +import com.oracle.svm.core.layeredimagesingleton.FeatureSingleton; +import com.oracle.svm.hosted.FeatureImpl; + +@AutomaticallyRegisteredFeature +public final class DynamicHubOffsetsFeature implements InternalFeature, FeatureSingleton { + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + ImageSingletons.add(DynamicHubOffsets.class, new DynamicHubOffsets()); + } + + @Override + public void beforeCompilation(BeforeCompilationAccess a) { + DynamicHubOffsets.singleton().initializeOffsets(((FeatureImpl.BeforeCompilationAccessImpl) a).getMetaAccess()); + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/KnownOffsetsFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/KnownOffsetsFeature.java index bdce9d509380..7d950ba61a05 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/KnownOffsetsFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/KnownOffsetsFeature.java @@ -37,7 +37,6 @@ import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.graal.meta.KnownOffsets; -import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.layeredimagesingleton.FeatureSingleton; import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton; import com.oracle.svm.core.stack.JavaFrameAnchor; @@ -72,8 +71,6 @@ public void beforeCompilation(BeforeCompilationAccess a) { int vtableEntrySize = dynamicHubLayout.vTableSlotSize; int typeIDSlotsOffset = SubstrateOptions.useClosedTypeWorldHubLayout() ? dynamicHubLayout.getClosedTypeWorldTypeCheckSlotsOffset() : -1; - int componentHubOffset = findFieldOffset(access, DynamicHub.class, "componentType"); - int javaFrameAnchorLastSPOffset = findStructOffset(access, JavaFrameAnchor.class, "getLastJavaSP"); int javaFrameAnchorLastIPOffset = findStructOffset(access, JavaFrameAnchor.class, "getLastJavaIP"); @@ -81,7 +78,7 @@ public void beforeCompilation(BeforeCompilationAccess a) { int imageCodeInfoCodeStartOffset = findFieldOffset(access, ImageCodeInfo.class, "codeStart"); - KnownOffsets.singleton().setLazyState(vtableBaseOffset, vtableEntrySize, typeIDSlotsOffset, componentHubOffset, + KnownOffsets.singleton().setLazyState(vtableBaseOffset, vtableEntrySize, typeIDSlotsOffset, javaFrameAnchorLastSPOffset, javaFrameAnchorLastIPOffset, vmThreadStatusOffset, imageCodeInfoCodeStartOffset); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DynamicHubPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DynamicHubPlugin.java new file mode 100644 index 000000000000..3c65f2c8a445 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DynamicHubPlugin.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024, 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 + * 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. + */ +package com.oracle.svm.hosted.substitute; + +import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.util.VMError; + +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; + +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaType; + +public class DynamicHubPlugin implements NodePlugin { + + @Override + public boolean handleNewInstance(GraphBuilderContext b, ResolvedJavaType type) { + if (b.getMetaAccess().lookupJavaType(DynamicHub.class).isAssignableFrom(type)) { + // GR-60200: This should never be reached, but is reached by serialization code. + // throw VMError.shouldNotReachHere("Using 'new' for DynamicHub is not permitted"); + } + return false; + } + + @Override + public boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) { + ResolvedJavaType dynamicHubType = b.getMetaAccess().lookupJavaType(DynamicHub.class); + + if (dynamicHubType.isAssignableFrom(field.getDeclaringClass())) { + throw VMError.shouldNotReachHere("Stores to DynamicHub are not permitted, see documentation of DynamicHub."); + } + return false; + } +}