Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8288425: Footprint regression due MH creation when initializing StringConcatFactory #9154

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -722,8 +722,15 @@ private static int classIndex(Class<?> cl) {
private static final int[] PREPEND_FILTER_SECOND_PAIR_ARGS = new int[] { 0, 1, 4, 5 };

// Base MH for complex prepender combinators.
private static final MethodHandle PREPEND_BASE = MethodHandles.dropArguments(
MethodHandles.identity(long.class), 1, byte[].class);
private static @Stable MethodHandle PREPEND_BASE;
private static MethodHandle prependBase() {
MethodHandle base = PREPEND_BASE;
if (base == null) {
base = PREPEND_BASE = MethodHandles.dropArguments(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious about this idiom - couldn't this result in the PREPEND_BASE field being assigned twice, with objects that are morally identical, but could have different identities? (thus violating @Stable contract)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not a violation, it's relying on behavior not discussed by the @Stable doc, which refers to such behavior as "undefined".

It's a carefully correlated dance between the code, interpreter, and C2 relying on:

  1. safe publication of equivalent immutable structures with no dependence on their identity when operating on them;
  2. the field being set in the interpreter; and
  3. by the time C2 inlines prependBase the field is no longer be updated, thus C2 can replace the field access with its value.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I think I was missing (2)

MethodHandles.identity(long.class), 1, byte[].class);
}
return base;
}

private static final @Stable MethodHandle[][] DOUBLE_PREPENDERS = new MethodHandle[TYPE_COUNT][TYPE_COUNT];

Expand All @@ -733,7 +740,7 @@ private static MethodHandle prepender(String prefix, Class<?> cl, String prefix2
MethodHandle prepend = DOUBLE_PREPENDERS[idx1][idx2];
if (prepend == null) {
prepend = DOUBLE_PREPENDERS[idx1][idx2] =
MethodHandles.dropArguments(PREPEND_BASE, 2, cl, cl2);
MethodHandles.dropArguments(prependBase(), 2, cl, cl2);
}
prepend = MethodHandles.filterArgumentsWithCombiner(prepend, 0, prepender(prefix, cl),
PREPEND_FILTER_FIRST_ARGS);
Expand All @@ -750,7 +757,7 @@ private static MethodHandle prepender(int pos, String[] constants, Class<?>[] pt
return prepender(constants[pos], ptypes[pos], constants[pos + 1], ptypes[pos + 1]);
}
// build a tree from an unbound prepender, allowing us to bind the constants in a batch as a final step
MethodHandle prepend = PREPEND_BASE;
MethodHandle prepend = prependBase();
if (count == 3) {
prepend = MethodHandles.dropArguments(prepend, 2,
ptypes[pos], ptypes[pos + 1], ptypes[pos + 2]);
Expand Down