Skip to content

Commit

Permalink
[GR-59641] Basic infrastructure to create a DynamicHub at runtime
Browse files Browse the repository at this point in the history
Initial support to allocate a DynamicHub into dedicated chunks of the GC. Needs a separate allocation node (SubstrateNewDynamicHubNode) and appropriate lowering. Only Serial GC for now.

Co-authored-by: Thomas Garcia <[email protected]>
  • Loading branch information
lewurm and rakachan committed Dec 9, 2024
1 parent 2e0e746 commit 0b36730
Show file tree
Hide file tree
Showing 25 changed files with 927 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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 {
Expand All @@ -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. */
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -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
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
Loading

0 comments on commit 0b36730

Please sign in to comment.