Skip to content

Commit a2f155c

Browse files
committed
[GR-40145] Honor @contended.
PullRequest: graal/12583
2 parents 95218ff + 326479b commit a2f155c

File tree

2 files changed

+80
-25
lines changed

2 files changed

+80
-25
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,9 @@ public Boolean getValue(OptionValues values) {
448448
@Option(help = "Sets the step size (in bytes) for sequential prefetch instructions.")//
449449
public static final HostedOptionKey<Integer> AllocatePrefetchStepSize = new HostedOptionKey<>(64);
450450

451+
@Option(help = "How many bytes to pad fields and classes marked @Contended with.") //
452+
public static final HostedOptionKey<Integer> ContendedPaddingWidth = new HostedOptionKey<>(128);
453+
451454
/*
452455
* Isolate tear down options.
453456
*/

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java

Lines changed: 77 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
import java.util.Optional;
4040
import java.util.Set;
4141
import java.util.concurrent.ForkJoinTask;
42+
import java.util.function.Function;
43+
import java.util.stream.Collectors;
4244

4345
import org.graalvm.collections.Pair;
4446
import org.graalvm.compiler.core.common.NumUtil;
@@ -96,6 +98,7 @@
9698
import com.oracle.svm.hosted.substitute.DeletedMethod;
9799
import com.oracle.svm.util.ReflectionUtil;
98100

101+
import jdk.internal.vm.annotation.Contended;
99102
import jdk.vm.ci.meta.ConstantPool;
100103
import jdk.vm.ci.meta.ExceptionHandler;
101104
import jdk.vm.ci.meta.JavaKind;
@@ -390,7 +393,7 @@ public static boolean isKnownImmutableType(Class<?> clazz) {
390393
}
391394

392395
private void layoutInstanceFields() {
393-
layoutInstanceFields(hUniverse.getObjectClass(), ConfigurationValues.getObjectLayout().getFirstFieldOffset(), new HostedField[0]);
396+
layoutInstanceFields(hUniverse.getObjectClass(), ConfigurationValues.getObjectLayout().getFirstFieldOffset(), new HostedField[0], false);
394397
}
395398

396399
private static boolean mustReserveLengthField(HostedInstanceClass clazz) {
@@ -405,7 +408,7 @@ private static boolean mustReserveLengthField(HostedInstanceClass clazz) {
405408
return false;
406409
}
407410

408-
private void layoutInstanceFields(HostedInstanceClass clazz, int superSize, HostedField[] superFields) {
411+
private void layoutInstanceFields(HostedInstanceClass clazz, int superSize, HostedField[] superFields, boolean superFieldsContendedPadding) {
409412
ArrayList<HostedField> rawFields = new ArrayList<>();
410413
ArrayList<HostedField> orderedFields = new ArrayList<>();
411414
ObjectLayout layout = ConfigurationValues.getObjectLayout();
@@ -433,30 +436,45 @@ private void layoutInstanceFields(HostedInstanceClass clazz, int superSize, Host
433436
}
434437
}
435438

436-
// Sort so that a) all Object fields are consecutive, and b) bigger types come first.
437-
Collections.sort(rawFields, HostedUniverse.FIELD_COMPARATOR_RELAXED);
438-
439439
int nextOffset = startSize;
440-
while (rawFields.size() > 0) {
441-
boolean progress = false;
442-
for (int i = 0; i < rawFields.size(); i++) {
443-
HostedField field = rawFields.get(i);
444-
int fieldSize = layout.sizeInBytes(field.getStorageKind());
445440

446-
if (nextOffset % fieldSize == 0) {
447-
field.setLocation(nextOffset);
448-
nextOffset += fieldSize;
441+
boolean hasLeadingPadding = superFieldsContendedPadding;
442+
boolean isClassContended = clazz.isAnnotationPresent(Contended.class);
443+
if (!hasLeadingPadding && (isClassContended || (clazz.getSuperclass() != null && clazz.getSuperclass().isAnnotationPresent(Contended.class)))) {
444+
nextOffset += getContendedPadding();
445+
hasLeadingPadding = true;
446+
}
449447

450-
rawFields.remove(i);
451-
orderedFields.add(field);
452-
progress = true;
453-
break;
454-
}
455-
}
456-
if (!progress) {
457-
// Insert padding byte and try again.
458-
nextOffset++;
448+
int beginOfFieldsOffset = nextOffset;
449+
450+
/*
451+
* Sort and group fields so that fields marked @Contended(tag) are grouped by their tag,
452+
* placing unannotated fields first in the object, and so that within groups, a) all Object
453+
* fields are consecutive, and b) bigger types come first.
454+
*/
455+
Object uncontendedSentinel = new Object();
456+
Function<HostedField, Object> getAnnotationGroup = field -> Optional.ofNullable(field.getAnnotation(Contended.class)).<Object> map(Contended::value).orElse(uncontendedSentinel);
457+
Map<Object, ArrayList<HostedField>> contentionGroups = rawFields.stream()
458+
.sorted(HostedUniverse.FIELD_COMPARATOR_RELAXED)
459+
.collect(Collectors.groupingBy(getAnnotationGroup, Collectors.toCollection(ArrayList::new)));
460+
461+
ArrayList<HostedField> uncontendedFields = contentionGroups.remove(uncontendedSentinel);
462+
if (uncontendedFields != null) {
463+
assert !uncontendedFields.isEmpty();
464+
nextOffset = placeFields(uncontendedFields, nextOffset, orderedFields, layout);
465+
}
466+
467+
for (ArrayList<HostedField> groupFields : contentionGroups.values()) {
468+
boolean placedFieldsBefore = (nextOffset != beginOfFieldsOffset);
469+
if (placedFieldsBefore || !hasLeadingPadding) {
470+
nextOffset += getContendedPadding();
459471
}
472+
nextOffset = placeFields(groupFields, nextOffset, orderedFields, layout);
473+
}
474+
475+
boolean fieldsTrailingPadding = !contentionGroups.isEmpty();
476+
if (fieldsTrailingPadding) {
477+
nextOffset += getContendedPadding();
460478
}
461479

462480
int endOfFieldsOffset = nextOffset;
@@ -465,8 +483,6 @@ private void layoutInstanceFields(HostedInstanceClass clazz, int superSize, Host
465483
* Compute the offsets of the "synthetic" fields for this class (but not subclasses).
466484
* Synthetic fields are put after all the instance fields. They are included in the instance
467485
* size, but not in the offset passed to subclasses.
468-
*
469-
* TODO: Should there be a list of synthetic fields for a class?
470486
*/
471487

472488
// A reference to a {@link java.util.concurrent.locks.ReentrantLock for "synchronized" or
@@ -478,6 +494,11 @@ private void layoutInstanceFields(HostedInstanceClass clazz, int superSize, Host
478494
nextOffset += referenceFieldAlignmentAndSize;
479495
}
480496

497+
boolean placedSyntheticFields = (nextOffset != endOfFieldsOffset);
498+
if (isClassContended && (contentionGroups.isEmpty() || placedSyntheticFields)) {
499+
nextOffset += getContendedPadding();
500+
}
501+
481502
clazz.instanceFieldsWithoutSuper = orderedFields.toArray(new HostedField[orderedFields.size()]);
482503
clazz.instanceSize = layout.alignUp(nextOffset);
483504
clazz.afterFieldsOffset = nextOffset;
@@ -499,9 +520,40 @@ private void layoutInstanceFields(HostedInstanceClass clazz, int superSize, Host
499520
* possible because each class that needs a synthetic field gets its own synthetic
500521
* field at the end of its instance fields.
501522
*/
502-
layoutInstanceFields((HostedInstanceClass) subClass, endOfFieldsOffset, clazz.instanceFieldsWithSuper);
523+
layoutInstanceFields((HostedInstanceClass) subClass, endOfFieldsOffset, clazz.instanceFieldsWithSuper, fieldsTrailingPadding);
524+
}
525+
}
526+
}
527+
528+
private static int getContendedPadding() {
529+
Integer value = SubstrateOptions.ContendedPaddingWidth.getValue();
530+
return (value > 0) ? value : 0; // no alignment required, placing fields takes care of it
531+
}
532+
533+
private static int placeFields(ArrayList<HostedField> fields, int firstOffset, ArrayList<HostedField> orderedFields, ObjectLayout layout) {
534+
int nextOffset = firstOffset;
535+
while (!fields.isEmpty()) {
536+
boolean progress = false;
537+
for (int i = 0; i < fields.size(); i++) {
538+
HostedField field = fields.get(i);
539+
int fieldSize = layout.sizeInBytes(field.getStorageKind());
540+
541+
if (nextOffset % fieldSize == 0) {
542+
field.setLocation(nextOffset);
543+
nextOffset += fieldSize;
544+
545+
fields.remove(i);
546+
orderedFields.add(field);
547+
progress = true;
548+
break;
549+
}
550+
}
551+
if (!progress) {
552+
// Insert padding byte and try again.
553+
nextOffset++;
503554
}
504555
}
556+
return nextOffset;
505557
}
506558

507559
private void layoutStaticFields() {

0 commit comments

Comments
 (0)