All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.bytebuddy.benchmark.ClassByImplementationBenchmark Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2014 - Present Rafael Winterhalter
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.bytebuddy.benchmark;

import javassist.util.proxy.MethodFilter;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.benchmark.specimen.ExampleInterface;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.dynamic.scaffold.TypeValidation;
import net.bytebuddy.implementation.StubMethod;
import net.bytebuddy.pool.TypePool;
import net.bytebuddy.utility.nullability.AlwaysNull;
import net.bytebuddy.utility.nullability.MaybeNull;
import net.sf.cglib.proxy.CallbackHelper;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.FixedValue;
import net.sf.cglib.proxy.NoOp;
import org.openjdk.jmh.annotations.*;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.concurrent.TimeUnit;

import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy;
import static net.bytebuddy.matcher.ElementMatchers.none;

/**
 * 

* This benchmark dynamically creates a class which implements {@link net.bytebuddy.benchmark.specimen.ExampleInterface} * which overrides all methods to invoke the direct super class's implementation. The benchmark furthermore creates an * instance of this class since some code generation frameworks rely on this property. *

*

* Note that this class defines all values that are accessed by benchmark methods as instance fields. This way, the JIT * compiler's capability of constant folding is limited in order to produce more comparable test results. *

*/ @State(Scope.Thread) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) public class ClassByImplementationBenchmark { /** * The base class to be subclassed in all benchmarks. */ public static final Class BASE_CLASS = ExampleInterface.class; /** * The default reference value. By defining the default reference value as a string type instead of as an object * type, the field is inlined by the compiler, similar to the primitive values. */ @AlwaysNull public static final String DEFAULT_REFERENCE_VALUE = null; /** * The default {@code boolean} value. */ public static final boolean DEFAULT_BOOLEAN_VALUE = false; /** * The default {@code byte} value. */ public static final byte DEFAULT_BYTE_VALUE = 0; /** * The default {@code short} value. */ public static final short DEFAULT_SHORT_VALUE = 0; /** * The default {@code char} value. */ public static final char DEFAULT_CHAR_VALUE = 0; /** * The default {@code int} value. */ public static final int DEFAULT_INT_VALUE = 0; /** * The default {@code long} value. */ public static final long DEFAULT_LONG_VALUE = 0L; /** * The default {@code float} value. */ public static final float DEFAULT_FLOAT_VALUE = 0f; /** * The default {@code double} value. */ public static final double DEFAULT_DOUBLE_VALUE = 0d; /** * The base class to be subclassed in all benchmarks. */ private Class baseClass = BASE_CLASS; /** * The default reference value. By defining the default reference value as a string type instead of as an object * type, the field is inlined by the compiler, similar to the primitive values. */ private String defaultReferenceValue = DEFAULT_REFERENCE_VALUE; /** * The default {@code boolean} value. */ private boolean defaultBooleanValue = DEFAULT_BOOLEAN_VALUE; /** * The default {@code byte} value. */ private byte defaultByteValue = DEFAULT_BYTE_VALUE; /** * The default {@code short} value. */ private short defaultShortValue = DEFAULT_SHORT_VALUE; /** * The default {@code char} value. */ private char defaultCharValue = DEFAULT_CHAR_VALUE; /** * The default {@code int} value. */ private int defaultIntValue = DEFAULT_INT_VALUE; /** * The default {@code long} value. */ private long defaultLongValue = DEFAULT_LONG_VALUE; /** * The default {@code float} value. */ private float defaultFloatValue = DEFAULT_FLOAT_VALUE; /** * The default {@code double} value. */ private double defaultDoubleValue = DEFAULT_DOUBLE_VALUE; /** * The zero-length of the class loader's URL. */ private int urlLength = 0; /** * Creates a new class loader. By using a fresh class loader for each creation, we avoid name space issues. * A class loader's creation is part of the benchmark but since any test creates a class loader exactly once, * the benchmark remains valid. * * @return A new class loader. */ private ClassLoader newClassLoader() { return new URLClassLoader(new URL[urlLength]); } /** * A description of {@link ClassByExtensionBenchmark#baseClass}. */ @MaybeNull private TypeDescription baseClassDescription; /** * Sets up this benchmark. */ @Setup public void setup() { baseClassDescription = TypePool.Default.ofSystemLoader().describe(baseClass.getName()).resolve(); } /** * Creates a baseline for the benchmark. * * @return A simple object that is not transformed. */ @Benchmark public ExampleInterface baseline() { return new ExampleInterface() { /** * {@inheritDoc} */ public boolean method(boolean arg) { return false; } /** * {@inheritDoc} */ public byte method(byte arg) { return 0; } /** * {@inheritDoc} */ public short method(short arg) { return 0; } /** * {@inheritDoc} */ public int method(int arg) { return 0; } /** * {@inheritDoc} */ public char method(char arg) { return 0; } /** * {@inheritDoc} */ public long method(long arg) { return 0; } /** * {@inheritDoc} */ public float method(float arg) { return 0; } /** * {@inheritDoc} */ public double method(double arg) { return 0; } /** * {@inheritDoc} */ @AlwaysNull public Object method(Object arg) { return null; } /** * {@inheritDoc} */ @AlwaysNull public boolean[] method(boolean arg1, boolean arg2, boolean arg3) { return null; } /** * {@inheritDoc} */ @AlwaysNull public byte[] method(byte arg1, byte arg2, byte arg3) { return null; } /** * {@inheritDoc} */ @AlwaysNull public short[] method(short arg1, short arg2, short arg3) { return null; } /** * {@inheritDoc} */ @AlwaysNull public int[] method(int arg1, int arg2, int arg3) { return null; } /** * {@inheritDoc} */ @AlwaysNull public char[] method(char arg1, char arg2, char arg3) { return null; } /** * {@inheritDoc} */ @AlwaysNull public long[] method(long arg1, long arg2, long arg3) { return null; } /** * {@inheritDoc} */ @AlwaysNull public float[] method(float arg1, float arg2, float arg3) { return null; } /** * {@inheritDoc} */ @AlwaysNull public double[] method(double arg1, double arg2, double arg3) { return null; } /** * {@inheritDoc} */ @AlwaysNull public Object[] method(Object arg1, Object arg2, Object arg3) { return null; } }; } /** * Performs a benchmark of an interface implementation using Byte Buddy. * * @return The created instance, in order to avoid JIT removal. * @throws java.lang.Exception If the reflective invocation causes an exception. */ @Benchmark public ExampleInterface benchmarkByteBuddy() throws Exception { return new ByteBuddy() .with(TypeValidation.DISABLED) .ignore(none()) .subclass(baseClass) .method(isDeclaredBy(baseClass)).intercept(StubMethod.INSTANCE) .make() .load(newClassLoader(), ClassLoadingStrategy.Default.INJECTION) .getLoaded() .getDeclaredConstructor() .newInstance(); } /** * Performs a benchmark of an interface implementation using Byte Buddy. This benchmark uses a type pool to compare against * usage of the reflection API. * * @return The created instance, in order to avoid JIT removal. * @throws java.lang.Exception If the reflective invocation causes an exception. */ @Benchmark public ExampleInterface benchmarkByteBuddyWithTypePool() throws Exception { return (ExampleInterface) new ByteBuddy() .with(TypeValidation.DISABLED) .ignore(none()) .subclass(baseClassDescription) .method(isDeclaredBy(baseClassDescription)).intercept(StubMethod.INSTANCE) .make() .load(newClassLoader(), ClassLoadingStrategy.Default.INJECTION) .getLoaded() .getDeclaredConstructor() .newInstance(); } /** * Performs a benchmark of an interface implementation using cglib. * * @return The created instance, in order to avoid JIT removal. */ @Benchmark public ExampleInterface benchmarkCglib() { Enhancer enhancer = new Enhancer(); enhancer.setUseCache(false); enhancer.setClassLoader(newClassLoader()); enhancer.setSuperclass(baseClass); CallbackHelper callbackHelper = new CallbackHelper(Object.class, new Class[]{baseClass}) { protected Object getCallback(Method method) { if (method.getDeclaringClass() == baseClass) { return new FixedValue() { public Object loadObject() { return null; } }; } else { return NoOp.INSTANCE; } } }; enhancer.setCallbackFilter(callbackHelper); enhancer.setCallbacks(callbackHelper.getCallbacks()); return (ExampleInterface) enhancer.create(); } /** * Performs a benchmark of an interface implementation using javassist proxies. * * @return The created instance, in order to avoid JIT removal. * @throws java.lang.Exception If the reflective invocation causes an exception. */ @Benchmark public ExampleInterface benchmarkJavassist() throws Exception { ProxyFactory proxyFactory = new ProxyFactory() { protected ClassLoader getClassLoader() { return newClassLoader(); } }; proxyFactory.setUseCache(false); proxyFactory.setUseWriteReplace(false); proxyFactory.setSuperclass(Object.class); proxyFactory.setInterfaces(new Class[]{baseClass}); proxyFactory.setFilter(new MethodFilter() { public boolean isHandled(Method method) { return true; } }); @SuppressWarnings("unchecked") Object instance = proxyFactory.createClass().getDeclaredConstructor().newInstance(); ((javassist.util.proxy.Proxy) instance).setHandler(new MethodHandler() { public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable { Class returnType = thisMethod.getReturnType(); if (returnType.isPrimitive()) { if (returnType == boolean.class) { return defaultBooleanValue; } else if (returnType == byte.class) { return defaultByteValue; } else if (returnType == short.class) { return defaultShortValue; } else if (returnType == char.class) { return defaultCharValue; } else if (returnType == int.class) { return defaultIntValue; } else if (returnType == long.class) { return defaultLongValue; } else if (returnType == float.class) { return defaultFloatValue; } else { return defaultDoubleValue; } } else { return defaultReferenceValue; } } }); return (ExampleInterface) instance; } /** * Performs a benchmark of an interface implementation using the Java Class Library's utilities. * * @return The created instance, in order to avoid JIT removal. * @throws java.lang.Exception If the reflective invocation causes an exception. */ @Benchmark public ExampleInterface benchmarkJdkProxy() throws Exception { return (ExampleInterface) Proxy.newProxyInstance(newClassLoader(), new Class[]{baseClass}, new InvocationHandler() { @MaybeNull public Object invoke(Object proxy, Method method, @MaybeNull Object[] argument) { Class returnType = method.getReturnType(); if (returnType.isPrimitive()) { if (returnType == boolean.class) { return defaultBooleanValue; } else if (returnType == byte.class) { return defaultByteValue; } else if (returnType == short.class) { return defaultShortValue; } else if (returnType == char.class) { return defaultCharValue; } else if (returnType == int.class) { return defaultIntValue; } else if (returnType == long.class) { return defaultLongValue; } else if (returnType == float.class) { return defaultFloatValue; } else { return defaultDoubleValue; } } else { return defaultReferenceValue; } } } ); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy