Skip to content

Commit

Permalink
8265135: Reduce work initializing VarForms
Browse files Browse the repository at this point in the history
Reviewed-by: psandoz, mchung
  • Loading branch information
cl4es committed Apr 19, 2021
1 parent d9e40dd commit 5303ccb
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 49 deletions.
17 changes: 14 additions & 3 deletions src/java.base/share/classes/java/lang/invoke/MethodHandles.java
Original file line number Diff line number Diff line change
Expand Up @@ -3644,9 +3644,8 @@ MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type

MemberName resolveOrFail(byte refKind, Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
checkSymbolicClass(refc); // do this before attempting to resolve
Objects.requireNonNull(name);
Objects.requireNonNull(type);
checkMethodName(refKind, name); // NPE check on name
checkMethodName(refKind, name); // implicit null-check of name
return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(), allowedModes,
NoSuchMethodException.class);
}
Expand All @@ -3669,6 +3668,19 @@ MemberName resolveOrNull(byte refKind, MemberName member) {
return IMPL_NAMES.resolveOrNull(refKind, member, lookupClassOrNull(), allowedModes);
}

MemberName resolveOrNull(byte refKind, Class<?> refc, String name, MethodType type) {
// do this before attempting to resolve
if (!isClassAccessible(refc)) {
return null;
}
Objects.requireNonNull(type);
// implicit null-check of name
if (name.startsWith("<") && refKind != REF_newInvokeSpecial) {
return null;
}
return IMPL_NAMES.resolveOrNull(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(), allowedModes);
}

void checkSymbolicClass(Class<?> refc) throws IllegalAccessException {
if (!isClassAccessible(refc)) {
throw new MemberName(refc).makeAccessException("symbolic reference class is not accessible", this);
Expand All @@ -3687,7 +3699,6 @@ void checkMethodName(byte refKind, String name) throws NoSuchMethodException {
throw new NoSuchMethodException("illegal method name: "+name);
}


/**
* Find my trustable caller class if m is a caller sensitive method.
* If this lookup object has original full privilege access, then the caller class is the lookupClass.
Expand Down
87 changes: 49 additions & 38 deletions src/java.base/share/classes/java/lang/invoke/VarForm.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/
package java.lang.invoke;

import jdk.internal.vm.annotation.DontInline;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Stable;

Expand All @@ -33,18 +34,24 @@
import java.util.ArrayList;
import java.util.List;

import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;

/**
* A var handle form containing a set of member name, one for each operation.
* Each member characterizes a static method.
*/
final class VarForm {

final Class<?> implClass;

final @Stable MethodType[] methodType_table;

final @Stable MemberName[] memberName_table;

VarForm(Class<?> implClass, Class<?> receiver, Class<?> value, Class<?>... intermediate) {
this.methodType_table = new MethodType[VarHandle.AccessType.values().length];
this.memberName_table = new MemberName[VarHandle.AccessMode.values().length];
this.implClass = implClass;
if (receiver == null) {
initMethodTypes(value, intermediate);
} else {
Expand All @@ -53,37 +60,46 @@ final class VarForm {
System.arraycopy(intermediate, 0, coordinates, 1, intermediate.length);
initMethodTypes(value, coordinates);
}

// TODO lazily calculate
this.memberName_table = linkFromStatic(implClass);
}

// Used by IndirectVarHandle
VarForm(Class<?> value, Class<?>[] coordinates) {
this.methodType_table = new MethodType[VarHandle.AccessType.values().length];
this.memberName_table = null;
this.implClass = null;
initMethodTypes(value, coordinates);
}

void initMethodTypes(Class<?> value, Class<?>... coordinates) {
Class<?> erasedValue = MethodTypeForm.canonicalize(value, MethodTypeForm.ERASE);
Class<?>[] erasedCoordinates = MethodTypeForm.canonicalizeAll(coordinates, MethodTypeForm.ERASE);

if (erasedValue != null) {
value = erasedValue;
}
if (erasedCoordinates != null) {
coordinates = erasedCoordinates;
}

MethodType type = MethodType.methodType(value, coordinates);

// (Receiver, <Intermediates>)Value
methodType_table[VarHandle.AccessType.GET.ordinal()] =
MethodType.methodType(value, coordinates).erase();
methodType_table[VarHandle.AccessType.GET.ordinal()] = type;

// (Receiver, <Intermediates>, Value)Value
type = methodType_table[VarHandle.AccessType.GET_AND_UPDATE.ordinal()] =
type.appendParameterTypes(value);

// (Receiver, <Intermediates>, Value)void
methodType_table[VarHandle.AccessType.SET.ordinal()] =
MethodType.methodType(void.class, coordinates).appendParameterTypes(value).erase();
methodType_table[VarHandle.AccessType.SET.ordinal()] = type.changeReturnType(void.class);

// (Receiver, <Intermediates>, Value)Value
methodType_table[VarHandle.AccessType.GET_AND_UPDATE.ordinal()] =
MethodType.methodType(value, coordinates).appendParameterTypes(value).erase();
// (Receiver, <Intermediates>, Value, Value)Value
type = methodType_table[VarHandle.AccessType.COMPARE_AND_EXCHANGE.ordinal()] =
type.appendParameterTypes(value);

// (Receiver, <Intermediates>, Value, Value)boolean
methodType_table[VarHandle.AccessType.COMPARE_AND_SET.ordinal()] =
MethodType.methodType(boolean.class, coordinates).appendParameterTypes(value, value).erase();

// (Receiver, <Intermediates>, Value, Value)Value
methodType_table[VarHandle.AccessType.COMPARE_AND_EXCHANGE.ordinal()] =
MethodType.methodType(value, coordinates).appendParameterTypes(value, value).erase();
type.changeReturnType(boolean.class);
}

@ForceInline
Expand All @@ -93,14 +109,30 @@ final MethodType getMethodType(int type) {

@ForceInline
final MemberName getMemberName(int mode) {
// TODO calculate lazily
MemberName mn = memberName_table[mode];
MemberName mn = getMemberNameOrNull(mode);
if (mn == null) {
throw new UnsupportedOperationException();
}
return mn;
}

@ForceInline
final MemberName getMemberNameOrNull(int mode) {
MemberName mn = memberName_table[mode];
if (mn == null) {
mn = resolveMemberName(mode);
}
return mn;
}

@DontInline
MemberName resolveMemberName(int mode) {
AccessMode value = AccessMode.values()[mode];
String methodName = value.methodName();
MethodType type = methodType_table[value.at.ordinal()].insertParameterTypes(0, VarHandle.class);
return memberName_table[mode] = MethodHandles.Lookup.IMPL_LOOKUP
.resolveOrNull(REF_invokeStatic, implClass, methodName, type);
}

@Stable
MethodType[] methodType_V_table;
Expand All @@ -125,25 +157,4 @@ final MethodType getMethodType_V(int type) {
}
return table[type];
}


/**
* Link all signature polymorphic methods.
*/
private static MemberName[] linkFromStatic(Class<?> implClass) {
MemberName[] table = new MemberName[AccessMode.values().length];

for (Class<?> c = implClass; c != VarHandle.class; c = c.getSuperclass()) {
for (Method m : c.getDeclaredMethods()) {
if (Modifier.isStatic(m.getModifiers())) {
AccessMode am = AccessMode.methodNameToAccessMode.get(m.getName());
if (am != null) {
assert table[am.ordinal()] == null;
table[am.ordinal()] = new MemberName(m);
}
}
}
}
return table;
}
}
10 changes: 2 additions & 8 deletions src/java.base/share/classes/java/lang/invoke/VarHandle.java
Original file line number Diff line number Diff line change
Expand Up @@ -1938,11 +1938,6 @@ public static AccessMode valueFromMethodName(String methodName) {
if (am != null) return am;
throw new IllegalArgumentException("No AccessMode value for method name " + methodName);
}

@ForceInline
static MemberName getMemberName(int ordinal, VarForm vform) {
return vform.memberName_table[ordinal];
}
}

static final class AccessDescriptor {
Expand Down Expand Up @@ -2045,7 +2040,7 @@ final MethodType accessModeTypeUncached(int accessTypeOrdinal) {
* {@code false}.
*/
public final boolean isAccessModeSupported(AccessMode accessMode) {
return AccessMode.getMemberName(accessMode.ordinal(), vform) != null;
return vform.getMemberNameOrNull(accessMode.ordinal()) != null;
}

/**
Expand All @@ -2068,8 +2063,7 @@ public final boolean isAccessModeSupported(AccessMode accessMode) {
* @return a method handle bound to this VarHandle and the given access mode
*/
public MethodHandle toMethodHandle(AccessMode accessMode) {
MemberName mn = AccessMode.getMemberName(accessMode.ordinal(), vform);
if (mn != null) {
if (isAccessModeSupported(accessMode)) {
MethodHandle mh = getMethodHandle(accessMode.ordinal());
return mh.bindTo(this);
}
Expand Down

1 comment on commit 5303ccb

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

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

Please sign in to comment.