8302666: Replace CHM with VarHandle in ForeachOrderedTask

Reviewed-by: psandoz
This commit is contained in:
Viktor Klang 2023-03-10 16:01:12 +00:00 committed by Paul Sandoz
parent a32ee5dd8b
commit f2a36b4b52

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,13 +26,14 @@ package java.util.stream;
import java.util.Objects;
import java.util.Spliterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountedCompleter;
import java.util.function.Consumer;
import java.util.function.DoubleConsumer;
import java.util.function.IntConsumer;
import java.util.function.IntFunction;
import java.util.function.LongConsumer;
import java.lang.invoke.VarHandle;
import java.lang.invoke.MethodHandles;
/**
* Factory for creating instances of {@code TerminalOp} that perform an
@ -364,11 +365,21 @@ final class ForEachOps {
private final PipelineHelper<T> helper;
private Spliterator<S> spliterator;
private final long targetSize;
private final ConcurrentHashMap<ForEachOrderedTask<S, T>, ForEachOrderedTask<S, T>> completionMap;
private final Sink<T> action;
private final ForEachOrderedTask<S, T> leftPredecessor;
private Node<T> node;
private ForEachOrderedTask<S, T> next;
private static final VarHandle NEXT;
static {
try {
MethodHandles.Lookup l = MethodHandles.lookup();
NEXT = l.findVarHandle(ForEachOrderedTask.class, "next", ForEachOrderedTask.class);
} catch (Exception e) {
throw new InternalError(e);
}
}
protected ForEachOrderedTask(PipelineHelper<T> helper,
Spliterator<S> spliterator,
Sink<T> action) {
@ -376,8 +387,6 @@ final class ForEachOps {
this.helper = helper;
this.spliterator = spliterator;
this.targetSize = AbstractTask.suggestTargetSize(spliterator.estimateSize());
// Size map to avoid concurrent re-sizes
this.completionMap = new ConcurrentHashMap<>(Math.max(16, AbstractTask.getLeafTarget() << 1));
this.action = action;
this.leftPredecessor = null;
}
@ -389,7 +398,6 @@ final class ForEachOps {
this.helper = parent.helper;
this.spliterator = spliterator;
this.targetSize = parent.targetSize;
this.completionMap = parent.completionMap;
this.action = parent.action;
this.leftPredecessor = leftPredecessor;
}
@ -410,6 +418,10 @@ final class ForEachOps {
ForEachOrderedTask<S, T> rightChild =
new ForEachOrderedTask<>(task, rightSplit, leftChild);
// leftChild and rightChild were just created and not fork():ed
// yet so no need for a volatile write
leftChild.next = rightChild;
// Fork the parent task
// Completion of the left and right children "happens-before"
// completion of the parent
@ -417,7 +429,6 @@ final class ForEachOps {
// Completion of the left child "happens-before" completion of
// the right child
rightChild.addToPendingCount(1);
task.completionMap.put(leftChild, rightChild);
// If task is not on the left spine
if (task.leftPredecessor != null) {
@ -433,7 +444,7 @@ final class ForEachOps {
leftChild.addToPendingCount(1);
// Update association of left-predecessor to left-most
// leaf node of right subtree
if (task.completionMap.replace(task.leftPredecessor, task, leftChild)) {
if (NEXT.compareAndSet(task.leftPredecessor, task, leftChild)) {
// If replaced, adjust the pending count of the parent
// to complete when its children complete
task.addToPendingCount(-1);
@ -499,7 +510,7 @@ final class ForEachOps {
// "happens-before" completion of the associated left-most leaf task
// of right subtree (if any, which can be this task's right sibling)
//
ForEachOrderedTask<S, T> leftDescendant = completionMap.remove(this);
var leftDescendant = (ForEachOrderedTask<S, T>)NEXT.getAndSet(this, null);
if (leftDescendant != null)
leftDescendant.tryComplete();
}