8285633: Take better advantage of generic MethodType cache
Reviewed-by: jvernee
This commit is contained in:
parent
5b42747ba1
commit
6c79671e50
src/java.base/share/classes/java/lang/invoke
LambdaForm.javaMemberName.javaMethodHandleImpl.javaMethodHandleNatives.javaMethodHandles.javaMethodType.javaMethodTypeForm.java
test/micro/org/openjdk/bench/java/lang/invoke
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user