blob: 42b72ac06bb4f3d045d3a9345742af5081f0889a [file] [log] [blame]
/*
* Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Petros Splinakis - initial implementation
package org.eclipse.persistence.testing.perf.jpa.tests.basic;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
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.infra.Blackhole;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
/**
* Benchmarks for assessing performance improvement with usage of MethodHandle over java.lang.Method/Field.
*
* @author Petros Splinakis
*/
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class MethodHandleComparisonTests {
private static final class TestClass {
public Object object;
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
}
// Test objects
private TestClass testClass;
private Object object;
private static TestClass staticTestClass;
private static Object staticObject;
private static final TestClass staticFinalTestClass;
private static final Object staticFinalObject;
// Field access
private Field field;
private MethodHandle unreflectGetter;
private MethodHandle unreflectSetter;
private static Field staticField;
private static MethodHandle staticUnreflectGetter;
private static MethodHandle staticUnreflectSetter;
private static final Field staticFinalField;
private static final MethodHandle staticFinalUnreflectGetter;
private static final MethodHandle staticFinalUnreflectSetter;
// Accessor method access
private Method getter;
private Method setter;
private MethodHandle getterHandle;
private MethodHandle setterHandle;
private static Method staticGetter;
private static Method staticSetter;
private static MethodHandle staticGetterHandle;
private static MethodHandle staticSetterHandle;
private static final Method staticFinalGetter;
private static final Method staticFinalSetter;
private static final MethodHandle staticFinalGetterHandle;
private static final MethodHandle staticFinalSetterHandle;
// Static Setup
static {
staticTestClass = new TestClass();
staticObject = new Object();
staticFinalTestClass = staticTestClass;
staticFinalObject = staticObject;
MethodHandles.Lookup lookup = MethodHandles.lookup();
try {
// Direct field access
staticField = TestClass.class.getField("object");
staticUnreflectGetter = lookup.unreflectGetter(staticField);
staticUnreflectSetter = lookup.unreflectSetter(staticField);
staticFinalField = staticField;
staticFinalUnreflectGetter = staticUnreflectGetter;
staticFinalUnreflectSetter = staticUnreflectSetter;
// Accessor method access
staticGetter = TestClass.class.getMethod("getObject");
staticSetter = TestClass.class.getMethod("setObject", Object.class);
staticGetterHandle = lookup.unreflect(staticGetter);
staticSetterHandle = lookup.unreflect(staticSetter);
staticFinalGetter = staticGetter;
staticFinalSetter = staticSetter;
staticFinalGetterHandle = staticGetterHandle;
staticFinalSetterHandle = staticSetterHandle;
}
catch (Throwable t) {
throw new IllegalStateException(t);
}
}
@Setup
public void setup() {
testClass = staticTestClass;
object = staticObject;
field = staticField;
unreflectGetter = staticUnreflectGetter;
unreflectSetter = staticUnreflectSetter;
getter = staticGetter;
setter = staticSetter;
getterHandle = staticGetterHandle;
setterHandle = staticSetterHandle;
}
/**************************************
* Test using method local attributes *
**************************************/
@Benchmark
public void testDynamicGetValueField(Blackhole blackhole) throws Exception {
blackhole.consume(testClass.object);
}
@Benchmark
public void testDynamicGetValueFieldReflection(Blackhole blackhole) throws Exception {
blackhole.consume(TestClass.class.getField("object").get(testClass));
}
@Benchmark
public void testDynamicGetValueFieldMethodHandleReflection(Blackhole blackhole) throws Throwable {
blackhole.consume(MethodHandles.lookup().unreflectGetter(TestClass.class.getField("object")).invoke(testClass));
}
@Benchmark
public void testDynamicGetValueFieldMethodHandleReflectionExact(Blackhole blackhole) throws Throwable {
blackhole.consume(MethodHandles.lookup().unreflectGetter(TestClass.class.getField("object")).invokeExact(testClass));
}
@Benchmark
public void testDynamicGetValueFieldMethodHandle(Blackhole blackhole) throws Throwable {
blackhole.consume(MethodHandles.lookup().findGetter(TestClass.class, "object", Object.class).invoke(testClass));
}
@Benchmark
public void testDynamicGetValueFieldMethodHandleExact(Blackhole blackhole) throws Throwable {
blackhole.consume(MethodHandles.lookup().findGetter(TestClass.class, "object", Object.class).invokeExact(testClass));
}
@Benchmark
public void testDynamicSetValueField() throws Exception {
testClass.object = object;
}
@Benchmark
public void testDynamicSetValueFieldReflection() throws Exception {
TestClass.class.getField("object").set(testClass, object);
}
@Benchmark
public void testDynamicSetValueFieldMethodHandleReflection() throws Throwable {
MethodHandles.lookup().unreflectSetter(TestClass.class.getField("object")).invoke(testClass, object);
}
@Benchmark
public void testDynamicSetValueFieldMethodHandleReflectionExact() throws Throwable {
MethodHandles.lookup().unreflectSetter(TestClass.class.getField("object")).invokeExact(testClass, object);
}
@Benchmark
public void testDynamicSetValueFieldMethodHandle() throws Throwable {
MethodHandles.lookup().findSetter(TestClass.class, "object", Object.class).invoke(testClass, object);
}
@Benchmark
public void testDynamicSetValueFieldMethodHandleExact() throws Throwable {
MethodHandles.lookup().findSetter(TestClass.class, "object", Object.class).invokeExact(testClass, object);
}
@Benchmark
public void testDynamicGetValueMethod(Blackhole blackhole) throws Exception {
blackhole.consume(testClass.getObject());
}
@Benchmark
public void testDynamicGetValueMethodReflection(Blackhole blackhole) throws Exception {
blackhole.consume(TestClass.class.getMethod("getObject").invoke(testClass));
}
@Benchmark
public void testDynamicGetValueMethodMethodHandleReflection(Blackhole blackhole) throws Throwable {
blackhole.consume(MethodHandles.lookup().unreflect(TestClass.class.getMethod("getObject")).invoke(testClass));
}
@Benchmark
public void testDynamicGetValueMethodMethodHandleReflectionExact(Blackhole blackhole) throws Throwable {
blackhole.consume(MethodHandles.lookup().unreflect(TestClass.class.getMethod("getObject")).invokeExact(testClass));
}
@Benchmark
public void testDynamicGetValueMethodMethodHandle(Blackhole blackhole) throws Throwable {
blackhole.consume(MethodHandles.lookup().findVirtual(TestClass.class, "getObject", MethodType.methodType(Object.class)).invoke(testClass));
}
@Benchmark
public void testDynamicGetValueMethodMethodHandleExact(Blackhole blackhole) throws Throwable {
blackhole.consume(MethodHandles.lookup().findVirtual(TestClass.class, "getObject", MethodType.methodType(Object.class)).invokeExact(testClass));
}
@Benchmark
public void testDynamicSetValueMethod() throws Exception {
testClass.setObject(object);
}
@Benchmark
public void testDynamicSetValueMethodReflection() throws Exception {
TestClass.class.getMethod("setObject").invoke(testClass, object);
}
@Benchmark
public void testDynamicSetValueMethodMethodHandleReflection() throws Throwable {
MethodHandles.lookup().unreflect(TestClass.class.getMethod("setObject")).invoke(testClass, object);
}
@Benchmark
public void testDynamicSetValueMethodMethodHandleReflectionExact() throws Throwable {
MethodHandles.lookup().unreflect(TestClass.class.getMethod("setObject")).invokeExact(testClass, object);
}
@Benchmark
public void testDynamicSetValueMethodMethodHandle() throws Throwable {
MethodHandles.lookup().findVirtual(TestClass.class, "setObject", MethodType.methodType(Void.class, Object.class)).invoke(testClass, object);
}
@Benchmark
public void testDynamicSetValueMethodMethodHandleExact() throws Throwable {
MethodHandles.lookup().findVirtual(TestClass.class, "setObject", MethodType.methodType(Void.class, Object.class)).invokeExact(testClass, object);
}
/**********************************
* Test using instance attributes *
**********************************/
@Benchmark
public void testGetValueField(Blackhole blackhole) throws Exception {
blackhole.consume(testClass.object);
}
@Benchmark
public void testGetValueFieldReflection(Blackhole blackhole) throws Exception {
blackhole.consume(field.get(testClass));
}
@Benchmark
public void testGetValueFieldMethodHandle(Blackhole blackhole) throws Throwable {
blackhole.consume(unreflectGetter.invoke(testClass));
}
@Benchmark
public void testGetValueFieldMethodHandleExact(Blackhole blackhole) throws Throwable {
blackhole.consume(unreflectGetter.invokeExact(testClass));
}
@Benchmark
public void testSetValueField() throws Exception {
testClass.object = object;
}
@Benchmark
public void testSetValueFieldReflection() throws Exception {
field.set(testClass, object);
}
@Benchmark
public void testSetValueFieldMethodHandle() throws Throwable {
unreflectSetter.invoke(testClass, object);
}
@Benchmark
public void testSetValueFieldMethodHandleExact() throws Throwable {
unreflectSetter.invokeExact(testClass, object);
}
@Benchmark
public void testGetValueMethod(Blackhole blackhole) throws Exception {
blackhole.consume(testClass.getObject());
}
@Benchmark
public void testGetValueMethodReflection(Blackhole blackhole) throws Exception {
blackhole.consume(getter.invoke(testClass));
}
@Benchmark
public void testGetValueMethodMethodHandle(Blackhole blackhole) throws Throwable {
blackhole.consume(getterHandle.invoke(testClass));
}
@Benchmark
public void testGetValueMethodMethodHandleExact(Blackhole blackhole) throws Throwable {
blackhole.consume(getterHandle.invokeExact(testClass));
}
@Benchmark
public void testSetValueMethod() throws Exception {
testClass.setObject(object);
}
@Benchmark
public void testSetValueMethodReflection() throws Exception {
setter.invoke(testClass, object);
}
@Benchmark
public void testSetValueMethodMethodHandle() throws Throwable {
setterHandle.invoke(testClass, object);
}
@Benchmark
public void testSetValueMethodMethodHandleExact() throws Throwable {
setterHandle.invokeExact(testClass, object);
}
/********************************
* Test using static attributes *
********************************/
@Benchmark
public void testStaticGetValueField(Blackhole blackhole) throws Exception {
blackhole.consume(staticTestClass.object);
}
@Benchmark
public void testStaticGetValueFieldReflection(Blackhole blackhole) throws Exception {
blackhole.consume(staticField.get(staticTestClass));
}
@Benchmark
public void testStaticGetValueFieldMethodHandle(Blackhole blackhole) throws Throwable {
blackhole.consume(staticUnreflectGetter.invoke(staticTestClass));
}
@Benchmark
public void testStaticGetValueFieldMethodHandleExact(Blackhole blackhole) throws Throwable {
blackhole.consume(staticUnreflectGetter.invokeExact(staticTestClass));
}
@Benchmark
public void testStaticSetValueField() throws Exception {
staticTestClass.object = staticObject;
}
@Benchmark
public void testStaticSetValueFieldReflection() throws Exception {
staticField.set(staticTestClass, staticObject);
}
@Benchmark
public void testStaticSetValueFieldMethodHandle() throws Throwable {
staticUnreflectSetter.invoke(staticTestClass, staticObject);
}
@Benchmark
public void testStaticSetValueFieldMethodHandleExact() throws Throwable {
staticUnreflectSetter.invokeExact(staticTestClass, staticObject);
}
@Benchmark
public void testStaticGetValueMethod(Blackhole blackhole) throws Exception {
blackhole.consume(staticTestClass.getObject());
}
@Benchmark
public void testStaticGetValueMethodReflection(Blackhole blackhole) throws Exception {
blackhole.consume(staticGetter.invoke(staticTestClass));
}
@Benchmark
public void testStaticGetValueMethodMethodHandle(Blackhole blackhole) throws Throwable {
blackhole.consume(staticGetterHandle.invoke(staticTestClass));
}
@Benchmark
public void testStaticGetValueMethodMethodHandleExact(Blackhole blackhole) throws Throwable {
blackhole.consume(staticGetterHandle.invokeExact(staticTestClass));
}
@Benchmark
public void testStaticSetValueMethod() throws Exception {
staticTestClass.setObject(staticObject);
}
@Benchmark
public void testStaticSetValueMethodReflection() throws Exception {
staticSetter.invoke(staticTestClass, staticObject);
}
@Benchmark
public void testStaticSetValueMethodMethodHandle() throws Throwable {
staticSetterHandle.invoke(staticTestClass, staticObject);
}
@Benchmark
public void testStaticSetValueMethodMethodHandleExact() throws Throwable {
staticSetterHandle.invokeExact(staticTestClass, staticObject);
}
/**************************************
* Test using static final attributes *
**************************************/
@Benchmark
public void testStaticFinalGetValueField(Blackhole blackhole) throws Exception {
blackhole.consume(staticFinalTestClass.object);
}
@Benchmark
public void testStaticFinalGetValueFieldReflection(Blackhole blackhole) throws Exception {
blackhole.consume(staticFinalField.get(staticFinalTestClass));
}
@Benchmark
public void testStaticFinalGetValueFieldMethodHandle(Blackhole blackhole) throws Throwable {
blackhole.consume(staticFinalUnreflectGetter.invoke(staticFinalTestClass));
}
@Benchmark
public void testStaticFinalGetValueFieldMethodHandleExact(Blackhole blackhole) throws Throwable {
blackhole.consume(staticFinalUnreflectGetter.invokeExact(staticFinalTestClass));
}
@Benchmark
public void testStaticFinalSetValueField() throws Exception {
staticFinalTestClass.object = staticFinalObject;
}
@Benchmark
public void testStaticFinalSetValueFieldReflection() throws Exception {
staticFinalField.set(staticFinalTestClass, staticFinalObject);
}
@Benchmark
public void testStaticFinalSetValueFieldMethodHandle() throws Throwable {
staticFinalUnreflectSetter.invoke(staticFinalTestClass, staticFinalObject);
}
@Benchmark
public void testStaticFinalSetValueFieldMethodHandleExact() throws Throwable {
staticFinalUnreflectSetter.invokeExact(staticFinalTestClass, staticFinalObject);
}
@Benchmark
public void testStaticFinalGetValueMethod(Blackhole blackhole) throws Exception {
blackhole.consume(staticFinalTestClass.getObject());
}
@Benchmark
public void testStaticFinalGetValueMethodReflection(Blackhole blackhole) throws Exception {
blackhole.consume(staticFinalGetter.invoke(staticFinalTestClass));
}
@Benchmark
public void testStaticFinalGetValueMethodMethodHandle(Blackhole blackhole) throws Throwable {
blackhole.consume(staticFinalGetterHandle.invoke(staticFinalTestClass));
}
@Benchmark
public void testStaticFinalGetValueMethodMethodHandleExact(Blackhole blackhole) throws Throwable {
blackhole.consume(staticFinalGetterHandle.invokeExact(staticFinalTestClass));
}
@Benchmark
public void testStaticFinalSetValueMethod() throws Exception {
staticFinalTestClass.setObject(staticFinalObject);
}
@Benchmark
public void testStaticFinalSetValueMethodReflection() throws Exception {
staticFinalSetter.invoke(staticFinalTestClass, staticFinalObject);
}
@Benchmark
public void testStaticFinalSetValueMethodMethodHandle() throws Throwable {
staticFinalSetterHandle.invoke(staticFinalTestClass, staticFinalObject);
}
@Benchmark
public void testStaticFinalSetValueMethodMethodHandleExact() throws Throwable {
staticFinalSetterHandle.invokeExact(staticFinalTestClass, staticFinalObject);
}
}