8285633: Take better advantage of generic MethodType cache

Reviewed-by: jvernee
This commit is contained in:
Claes Redestad 2022-04-27 17:54:21 +00:00
parent 5b42747ba1
commit 6c79671e50
8 changed files with 118 additions and 23 deletions

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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
@ -622,7 +622,7 @@ class LambdaForm {
for (int i = 0; i < arity; ++i) {
ptypes[i] = parameterType(i).btClass;
}
return MethodType.makeImpl(returnType().btClass, ptypes, true);
return MethodType.methodType(returnType().btClass, ptypes, true);
}
/** Return ABC_Z, where the ABC are parameter type characters, and Z is the return type character. */

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -153,7 +153,7 @@ final class MemberName implements Member, Cloneable {
} else if (type instanceof Object[] typeInfo) {
Class<?>[] ptypes = (Class<?>[]) typeInfo[1];
Class<?> rtype = (Class<?>) typeInfo[0];
MethodType res = MethodType.makeImpl(rtype, ptypes, true);
MethodType res = MethodType.methodType(rtype, ptypes, true);
type = res;
}
// Make sure type is a MethodType for racing threads.

@ -323,7 +323,7 @@ abstract class MethodHandleImpl {
for (int pos : positions) {
ptypes[pos - 1] = newType;
}
midType = MethodType.makeImpl(midType.rtype(), ptypes, true);
midType = MethodType.methodType(midType.rtype(), ptypes, true);
}
LambdaForm form2;
if (positions.length > 1) {

@ -393,7 +393,7 @@ class MethodHandleNatives {
* The JVM wants a pointer to a MethodType. Oblige it by finding or creating one.
*/
static MethodType findMethodHandleType(Class<?> rtype, Class<?>[] ptypes) {
return MethodType.makeImpl(rtype, ptypes, true);
return MethodType.methodType(rtype, ptypes, true);
}
/**
@ -561,7 +561,7 @@ class MethodHandleNatives {
}
// Access descriptor at end
guardParams[guardParams.length - 1] = VarHandle.AccessDescriptor.class;
MethodType guardType = MethodType.makeImpl(guardReturnType, guardParams, true);
MethodType guardType = MethodType.methodType(guardReturnType, guardParams, true);
MemberName linker = new MemberName(
VarHandleGuards.class, getVarHandleGuardMethodName(guardType),

@ -5601,7 +5601,7 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
for (int pos : positions) {
ptypes[pos - 1] = newParamType;
}
MethodType newType = MethodType.makeImpl(targetType.rtype(), ptypes, true);
MethodType newType = MethodType.methodType(targetType.rtype(), ptypes, true);
LambdaForm lform = result.editor().filterRepeatedArgumentForm(BasicType.basicType(newParamType), positions);
return result.copyWithExtendL(newType, lform, filter);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -240,7 +240,7 @@ class MethodType
* @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
*/
public static MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
return makeImpl(rtype, ptypes, false);
return methodType(rtype, ptypes, false);
}
/**
@ -254,7 +254,7 @@ class MethodType
*/
public static MethodType methodType(Class<?> rtype, List<Class<?>> ptypes) {
boolean notrust = false; // random List impl. could return evil ptypes array
return makeImpl(rtype, listToArray(ptypes), notrust);
return methodType(rtype, listToArray(ptypes), notrust);
}
private static Class<?>[] listToArray(List<Class<?>> ptypes) {
@ -275,9 +275,23 @@ class MethodType
* @throws IllegalArgumentException if {@code ptype0} or {@code ptypes} or any element of {@code ptypes} is {@code void.class}
*/
public static MethodType methodType(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
Class<?>[] ptypes1 = new Class<?>[1+ptypes.length];
int len = ptypes.length;
if (rtype == Object.class && ptype0 == Object.class) {
if (len == 0) {
return genericMethodType(1, false);
}
if (isAllObject(ptypes, len - 1)) {
Class<?> lastParam = ptypes[len - 1];
if (lastParam == Object.class) {
return genericMethodType(len + 1, false);
} else if (lastParam == Object[].class) {
return genericMethodType(len, true);
}
}
}
Class<?>[] ptypes1 = new Class<?>[1 + len];
ptypes1[0] = ptype0;
System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
System.arraycopy(ptypes, 0, ptypes1, 1, len);
return makeImpl(rtype, ptypes1, true);
}
@ -290,6 +304,9 @@ class MethodType
* @throws NullPointerException if {@code rtype} is null
*/
public static MethodType methodType(Class<?> rtype) {
if (rtype == Object.class) {
return genericMethodType(0, false);
}
return makeImpl(rtype, NO_PTYPES, true);
}
@ -304,6 +321,13 @@ class MethodType
* @throws IllegalArgumentException if {@code ptype0} is {@code void.class}
*/
public static MethodType methodType(Class<?> rtype, Class<?> ptype0) {
if (rtype == Object.class) {
if (ptype0 == Object.class) {
return genericMethodType(1, false);
} else if (ptype0 == Object[].class) {
return genericMethodType(0, true);
}
}
return makeImpl(rtype, new Class<?>[]{ ptype0 }, true);
}
@ -318,7 +342,35 @@ class MethodType
* @throws NullPointerException if {@code rtype} or {@code ptypes} is null
*/
public static MethodType methodType(Class<?> rtype, MethodType ptypes) {
return makeImpl(rtype, ptypes.ptypes, true);
return methodType(rtype, ptypes.ptypes, true);
}
private static boolean isAllObject(Class<?>[] ptypes, int to) {
for (int i = 0; i < to; i++) {
if (ptypes[i] != Object.class) {
return false;
}
}
return true;
}
/*trusted*/
static MethodType methodType(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
if (rtype == Object.class) {
int last = ptypes.length - 1;
if (last < 0) {
return genericMethodType(0, false);
}
if (isAllObject(ptypes, last)) {
Class<?> lastParam = ptypes[last];
if (lastParam == Object.class) {
return genericMethodType(last + 1, false);
} else if (lastParam == Object[].class) {
return genericMethodType(last, true);
}
}
}
return makeImpl(rtype, ptypes, trusted);
}
/**
@ -332,8 +384,7 @@ class MethodType
* @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
* @return the unique method type of the desired structure
*/
/*trusted*/
static MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
private static MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
if (ptypes.length == 0) {
ptypes = NO_PTYPES; trusted = true;
}
@ -629,7 +680,7 @@ class MethodType
System.arraycopy(ptypes, end, nptypes, start, tail);
}
}
return makeImpl(rtype, nptypes, true);
return methodType(rtype, nptypes, true);
}
/**
@ -641,7 +692,7 @@ class MethodType
*/
public MethodType changeReturnType(Class<?> nrtype) {
if (returnType() == nrtype) return this;
return makeImpl(nrtype, ptypes, true);
return methodType(nrtype, ptypes, true);
}
/**
@ -1164,7 +1215,7 @@ class MethodType
List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader);
Class<?> rtype = types.remove(types.size() - 1);
Class<?>[] ptypes = listToArray(types);
return makeImpl(rtype, ptypes, true);
return methodType(rtype, ptypes, true);
}
/**

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -194,7 +194,7 @@ final class MethodTypeForm {
this.lambdaForms = new SoftReference[LF_LIMIT];
this.methodHandles = new SoftReference[MH_LIMIT];
} else {
this.basicType = MethodType.makeImpl(basicReturnType, basicPtypes, true);
this.basicType = MethodType.methodType(basicReturnType, basicPtypes, true);
// fill in rest of data from the basic type:
MethodTypeForm that = this.basicType.form();
assert(this != that);
@ -250,7 +250,7 @@ final class MethodTypeForm {
// Find the erased version of the method type:
if (rtypeCanonical == null) rtypeCanonical = rtype;
if (ptypesCanonical == null) ptypesCanonical = ptypes;
return MethodType.makeImpl(rtypeCanonical, ptypesCanonical, true);
return MethodType.methodType(rtypeCanonical, ptypesCanonical, true);
}
/** Canonicalize the given return or param type.

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2022, 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
@ -24,11 +24,14 @@ package org.openjdk.bench.java.lang.invoke;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import java.lang.invoke.MethodType;
import java.util.concurrent.TimeUnit;
@ -39,10 +42,16 @@ import java.util.concurrent.TimeUnit;
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
@Warmup(iterations = 10, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@Fork(3)
public class MethodTypeAcquire {
private MethodType pTypes;
private Class<?> objectType = Object.class;
private Class<?> otherType = A.class;
@Setup
public void setup() {
pTypes = MethodType.methodType(A.class, B.class);
@ -68,6 +77,21 @@ public class MethodTypeAcquire {
return MethodType.methodType(Object.class);
}
@Benchmark
public MethodType testGenericObject() {
return MethodType.genericMethodType(1);
}
@Benchmark
public MethodType testObjectObject() {
return MethodType.methodType(Object.class, Object.class);
}
@Benchmark
public MethodType testObjectObject_NonConst() {
return MethodType.methodType(objectType, objectType);
}
@Benchmark
public MethodType testSinglePType() {
return MethodType.methodType(void.class, int.class);
@ -78,6 +102,26 @@ public class MethodTypeAcquire {
return MethodType.methodType(void.class, A.class, B.class);
}
@Benchmark
public MethodType testMultiPType_ObjectAndA() {
return MethodType.methodType(Object.class, Object.class, Object.class, Object.class, Object.class, A.class, B.class);
}
@Benchmark
public MethodType testMultiPType_ObjectAndA_NonConst() {
return MethodType.methodType(objectType, objectType, objectType, objectType, objectType, otherType, otherType);
}
@Benchmark
public MethodType testMultiPType_ObjectOnly() {
return MethodType.methodType(Object.class, Object.class, Object.class, Object.class, Object.class, Object.class, Object.class);
}
@Benchmark
public MethodType testMultiPType_ObjectOnly_NonConst() {
return MethodType.methodType(objectType, objectType, objectType, objectType, objectType, objectType, objectType);
}
@Benchmark
public MethodType testMultiPType_Arg() {
return MethodType.methodType(void.class, pTypes);