diff -Nru byte-buddy-1.11.4/byte-buddy/pom.xml byte-buddy-1.12.21/byte-buddy/pom.xml
--- byte-buddy-1.11.4/byte-buddy/pom.xml 2021-06-19 21:31:07.000000000 +0000
+++ byte-buddy-1.12.21/byte-buddy/pom.xml 2023-01-04 22:45:00.000000000 +0000
@@ -5,7 +5,7 @@
- * Note: Byte Buddy does not execute code using an {@link java.security.AccessController}. If a security manager - * is present, the user of this class is responsible for assuring any required privileges. + * Note: Byte Buddy does not execute code using an {@code java.security.AccessController}. If a security manager + * is present, the user of this class is responsible for assuring any required privileges. To read an + * {@link Instrumentation}, the net.bytebuddy.agent.getInstrumentation runtime permission is required. *
*/ public class ByteBuddyAgent { /** - * Indicates that the agent should not resolve it's own code location for a self-attachment. + * Indicates that the agent should not resolve its own code location for a self-attachment. */ public static final String LATENT_RESOLVE = "net.bytebuddy.agent.latent"; @@ -91,7 +93,7 @@ /** * The size of the buffer for copying the agent installer file into another jar. */ - private static final int BUFFER_SIZE = 1024; + private static final int BUFFER_SIZE = 1024 * 8; /** * Convenience indices for reading and writing to the buffer to make the code more readable. @@ -104,18 +106,15 @@ private static final int SUCCESSFUL_ATTACH = 0; /** - * Base for access to a reflective member to make the code more readable. - */ - private static final Object STATIC_MEMBER = null; - - /** * Representation of the bootstrap {@link java.lang.ClassLoader}. */ + @AlwaysNull private static final ClassLoader BOOTSTRAP_CLASS_LOADER = null; /** * Represents a no-op argument for a dynamic agent attachment. */ + @AlwaysNull private static final String WITHOUT_ARGUMENT = null; /** @@ -161,11 +160,13 @@ /** * An indicator variable to express that no instrumentation is available. */ + @AlwaysNull private static final Instrumentation UNAVAILABLE = null; /** * Represents a failed attempt to self-resolve a jar file location. */ + @AlwaysNull private static final File CANNOT_SELF_RESOLVE = null; /** @@ -196,7 +197,7 @@ } catch (ClassNotFoundException ignored) { return action.run(); } catch (InvocationTargetException exception) { - throw new IllegalStateException("Failed to invoke access controller", exception.getCause()); + throw new IllegalStateException("Failed to invoke access controller", exception.getTargetException()); } catch (IllegalAccessException exception) { throw new IllegalStateException("Failed to access access controller", exception); } catch (NoSuchMethodException exception) { @@ -221,9 +222,10 @@ public static Instrumentation getInstrumentation() { Instrumentation instrumentation = doGetInstrumentation(); if (instrumentation == null) { - throw new IllegalStateException("The Byte Buddy agent is not initialized"); + throw new IllegalStateException("The Byte Buddy agent is not initialized or unavailable"); + } else { + return instrumentation; } - return instrumentation; } /** @@ -257,7 +259,7 @@ * @param processId The target process id. * @param argument The argument to provide to the agent. */ - public static void attach(File agentJar, String processId, String argument) { + public static void attach(File agentJar, String processId, @MaybeNull String argument) { attach(agentJar, processId, argument, AttachmentProvider.DEFAULT); } @@ -292,7 +294,7 @@ * @param argument The argument to provide to the agent. * @param attachmentProvider The attachment provider to use. */ - public static void attach(File agentJar, String processId, String argument, AttachmentProvider attachmentProvider) { + public static void attach(File agentJar, String processId, @MaybeNull String argument, AttachmentProvider attachmentProvider) { install(attachmentProvider, processId, argument, new AgentProvider.ForExistingAgent(agentJar), false); } @@ -327,7 +329,7 @@ * @param processProvider A provider of the target process id. * @param argument The argument to provide to the agent. */ - public static void attach(File agentJar, ProcessProvider processProvider, String argument) { + public static void attach(File agentJar, ProcessProvider processProvider, @MaybeNull String argument) { attach(agentJar, processProvider, argument, AttachmentProvider.DEFAULT); } @@ -362,7 +364,7 @@ * @param argument The argument to provide to the agent. * @param attachmentProvider The attachment provider to use. */ - public static void attach(File agentJar, ProcessProvider processProvider, String argument, AttachmentProvider attachmentProvider) { + public static void attach(File agentJar, ProcessProvider processProvider, @MaybeNull String argument, AttachmentProvider attachmentProvider) { install(attachmentProvider, processProvider.resolve(), argument, new AgentProvider.ForExistingAgent(agentJar), false); } @@ -397,7 +399,7 @@ * @param processId The target process id. * @param argument The argument to provide to the agent. */ - public static void attachNative(File agentLibrary, String processId, String argument) { + public static void attachNative(File agentLibrary, String processId, @MaybeNull String argument) { attachNative(agentLibrary, processId, argument, AttachmentProvider.DEFAULT); } @@ -432,7 +434,7 @@ * @param argument The argument to provide to the agent. * @param attachmentProvider The attachment provider to use. */ - public static void attachNative(File agentLibrary, String processId, String argument, AttachmentProvider attachmentProvider) { + public static void attachNative(File agentLibrary, String processId, @MaybeNull String argument, AttachmentProvider attachmentProvider) { install(attachmentProvider, processId, argument, new AgentProvider.ForExistingAgent(agentLibrary), true); } @@ -467,7 +469,7 @@ * @param processProvider A provider of the target process id. * @param argument The argument to provide to the agent. */ - public static void attachNative(File agentLibrary, ProcessProvider processProvider, String argument) { + public static void attachNative(File agentLibrary, ProcessProvider processProvider, @MaybeNull String argument) { attachNative(agentLibrary, processProvider, argument, AttachmentProvider.DEFAULT); } @@ -502,7 +504,7 @@ * @param argument The argument to provide to the agent. * @param attachmentProvider The attachment provider to use. */ - public static void attachNative(File agentLibrary, ProcessProvider processProvider, String argument, AttachmentProvider attachmentProvider) { + public static void attachNative(File agentLibrary, ProcessProvider processProvider, @MaybeNull String argument, AttachmentProvider attachmentProvider) { install(attachmentProvider, processProvider.resolve(), argument, new AgentProvider.ForExistingAgent(agentLibrary), true); } @@ -607,7 +609,7 @@ return instrumentation; } install(attachmentProvider, processProvider.resolve(), WITHOUT_ARGUMENT, AgentProvider.ForByteBuddyAgent.INSTANCE, false); - return doGetInstrumentation(); + return getInstrumentation(); } /** @@ -619,7 +621,7 @@ * @param agentProvider The agent provider for the agent jar or library. * @param isNative {@code true} if the agent is native. */ - private static void install(AttachmentProvider attachmentProvider, String processId, String argument, AgentProvider agentProvider, boolean isNative) { + private static void install(AttachmentProvider attachmentProvider, String processId, @MaybeNull String argument, AgentProvider agentProvider, boolean isNative) { AttachmentProvider.Accessor attachmentAccessor = attachmentProvider.attempt(); if (!attachmentAccessor.isAvailable()) { throw new IllegalStateException("No compatible attachment provider is available"); @@ -652,7 +654,7 @@ String processId, File agent, boolean isNative, - String argument) throws Exception { + @MaybeNull String argument) throws Exception { File selfResolvedJar = trySelfResolve(), attachmentJar = null; try { if (selfResolvedJar == null) { @@ -678,21 +680,22 @@ inputStream.close(); } } - StringBuilder classPath = new StringBuilder().append(quote((selfResolvedJar == null + StringBuilder classPath = new StringBuilder().append((selfResolvedJar == null ? attachmentJar - : selfResolvedJar).getCanonicalPath())); + : selfResolvedJar).getCanonicalPath()); for (File jar : externalAttachment.getClassPath()) { - classPath.append(File.pathSeparatorChar).append(quote(jar.getCanonicalPath())); + classPath.append(File.pathSeparatorChar).append(jar.getCanonicalPath()); } if (new ProcessBuilder(System.getProperty(JAVA_HOME) + File.separatorChar + "bin" + File.separatorChar + (System.getProperty(OS_NAME, "").toLowerCase(Locale.US).contains("windows") ? "java.exe" : "java"), + "-D" + Attacher.DUMP_PROPERTY + "=" + System.getProperty(Attacher.DUMP_PROPERTY, ""), CLASS_PATH_ARGUMENT, classPath.toString(), Attacher.class.getName(), externalAttachment.getVirtualMachineType(), processId, - quote(agent.getAbsolutePath()), + agent.getAbsolutePath(), Boolean.toString(isNative), argument == null ? "" : ("=" + argument)).start().waitFor() != SUCCESSFUL_ATTACH) { throw new IllegalStateException("Could not self-attach to current VM using external process"); @@ -711,7 +714,8 @@ * * @return The self-resolved jar file or {@code null} if the jar file cannot be located. */ - @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback") + @MaybeNull + @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback.") private static File trySelfResolve() { try { if (Boolean.getBoolean(LATENT_RESOLVE)) { @@ -740,30 +744,29 @@ } /** - * Quotes a value if it contains a white space. - * - * @param value The value to quote. - * @return The value being quoted if necessary. - */ - private static String quote(String value) { - return value.contains(" ") - ? '"' + value + '"' - : value; - } - - /** * Performs the actual lookup of the {@link java.lang.instrument.Instrumentation} from an installed - * Byte Buddy agent. + * Byte Buddy agent and returns the instance, or returns {@code null} if not present. * * @return The Byte Buddy agent's {@link java.lang.instrument.Instrumentation} instance. */ - @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Legal outcome where reflection communicates errors by throwing an exception") + @MaybeNull + @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback.") private static Instrumentation doGetInstrumentation() { try { - return (Instrumentation) ClassLoader.getSystemClassLoader() - .loadClass(Installer.class.getName()) + Class> installer = Class.forName(Installer.class.getName(), true, ClassLoader.getSystemClassLoader()); + try { + Class> module = Class.forName("java.lang.Module"); + Method getModule = Class.class.getMethod("getModule"); + Object source = getModule.invoke(ByteBuddyAgent.class), target = getModule.invoke(installer); + if (!((Boolean) module.getMethod("canRead", module).invoke(source, target))) { + module.getMethod("addReads", module).invoke(source, target); + } + } catch (ClassNotFoundException ignored) { + /* empty */ + } + return (Instrumentation) Class.forName(Installer.class.getName(), true, ClassLoader.getSystemClassLoader()) .getMethod(INSTRUMENTATION_METHOD) - .invoke(STATIC_MEMBER); + .invoke(null); } catch (Exception ignored) { return UNAVAILABLE; } @@ -952,10 +955,11 @@ * @param classPath The class path required to load the virtual machine class. * @return An appropriate accessor. */ - public static Accessor of(ClassLoader classLoader, File... classPath) { + public static Accessor of(@MaybeNull ClassLoader classLoader, File... classPath) { try { - return new Simple.WithExternalAttachment(classLoader.loadClass(VIRTUAL_MACHINE_TYPE_NAME), - Arrays.asList(classPath)); + return new Simple.WithExternalAttachment(Class.forName(VIRTUAL_MACHINE_TYPE_NAME, + false, + classLoader), Arrays.asList(classPath)); } catch (ClassNotFoundException ignored) { return Unavailable.INSTANCE; } @@ -1146,7 +1150,7 @@ /** * {@inheritDoc} */ - @SuppressFBWarnings(value = "DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED", justification = "Privilege is explicit user responsibility") + @SuppressFBWarnings(value = "DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED", justification = "Assuring privilege is explicit user responsibility.") public Accessor attempt() { File toolsJar = new File(System.getProperty(JAVA_HOME_PROPERTY), toolsJarPath); try { @@ -1177,7 +1181,7 @@ /** * {@inheritDoc} */ - @SuppressFBWarnings(value = "DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED", justification = "Privilege is explicit user responsibility") + @SuppressFBWarnings(value = "DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED", justification = "Assuring privilege is explicit user responsibility.") public Accessor attempt() { String location = System.getProperty(PROPERTY); if (location == null) { @@ -1309,7 +1313,9 @@ } /** - * A process provider for a legacy VM that reads the process id from its JMX properties. + * A process provider for a legacy VM that reads the process id from its JMX properties. This strategy + * is only used prior to Java 9 such that the java.management module never is resolved, even if + * the module system is used, as the module system was not available in any relevant JVM version. */ protected enum ForLegacyVm implements ProcessProvider { @@ -1321,8 +1327,15 @@ /** * {@inheritDoc} */ + @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback.") public String resolve() { - String runtimeName = ManagementFactory.getRuntimeMXBean().getName(); + String runtimeName; + try { + Method method = Class.forName("java.lang.management.ManagementFactory").getMethod("getRuntimeMXBean"); + runtimeName = (String) method.getReturnType().getMethod("getName").invoke(method.invoke(null)); + } catch (Exception exception) { + throw new IllegalStateException("Failed to access VM name via management factory", exception); + } int processIdIndex = runtimeName.indexOf('@'); if (processIdIndex == -1) { throw new IllegalStateException("Cannot extract process id from runtime management bean"); @@ -1364,7 +1377,7 @@ * * @return A dispatcher for the current VM. */ - @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback") + @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback.") public static ProcessProvider make() { try { return new ForJava9CapableVm(Class.forName("java.lang.ProcessHandle").getMethod("current"), @@ -1379,11 +1392,11 @@ */ public String resolve() { try { - return pid.invoke(current.invoke(STATIC_MEMBER)).toString(); + return pid.invoke(current.invoke(null)).toString(); } catch (IllegalAccessException exception) { throw new IllegalStateException("Cannot access Java 9 process API", exception); } catch (InvocationTargetException exception) { - throw new IllegalStateException("Error when accessing Java 9 process API", exception.getCause()); + throw new IllegalStateException("Error when accessing Java 9 process API", exception.getTargetException()); } } } @@ -1426,6 +1439,7 @@ * @return This jar file's location or {@code null} if this jar file's location is inaccessible. * @throws IOException If an I/O exception occurs. */ + @MaybeNull private static File trySelfResolve() throws IOException { ProtectionDomain protectionDomain = Installer.class.getProtectionDomain(); if (Boolean.getBoolean(LATENT_RESOLVE)) { @@ -1536,7 +1550,7 @@ /** * The supplied agent. */ - private File agent; + private final File agent; /** * Creates an agent provider for an existing agent. @@ -1587,7 +1601,7 @@ /** * {@inheritDoc} */ - @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback") + @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback.") public AttachmentTypeEvaluator run() { try { if (Boolean.getBoolean(JDK_ALLOW_SELF_ATTACH)) { @@ -1651,11 +1665,11 @@ */ public boolean requiresExternalAttachment(String processId) { try { - return pid.invoke(current.invoke(STATIC_MEMBER)).toString().equals(processId); + return pid.invoke(current.invoke(null)).toString().equals(processId); } catch (IllegalAccessException exception) { throw new IllegalStateException("Cannot access Java 9 process API", exception); } catch (InvocationTargetException exception) { - throw new IllegalStateException("Error when accessing Java 9 process API", exception.getCause()); + throw new IllegalStateException("Error when accessing Java 9 process API", exception.getTargetException()); } } } diff -Nru byte-buddy-1.11.4/byte-buddy-agent/src/main/java/net/bytebuddy/agent/Installer.java byte-buddy-1.12.21/byte-buddy-agent/src/main/java/net/bytebuddy/agent/Installer.java --- byte-buddy-1.11.4/byte-buddy-agent/src/main/java/net/bytebuddy/agent/Installer.java 2021-06-19 21:31:07.000000000 +0000 +++ byte-buddy-1.12.21/byte-buddy-agent/src/main/java/net/bytebuddy/agent/Installer.java 2023-01-04 22:45:00.000000000 +0000 @@ -15,6 +15,8 @@ */ package net.bytebuddy.agent; +import net.bytebuddy.agent.utility.nullability.MaybeNull; + import java.lang.instrument.Instrumentation; import java.lang.reflect.InvocationTargetException; import java.security.Permission; @@ -31,6 +33,7 @@ * of the Byte Buddy agent as this class might be loaded by a different class loader than the system class * loader. */ + @MaybeNull private static volatile Instrumentation instrumentation; /** @@ -56,14 +59,16 @@ try { Object securityManager = System.class.getMethod("getSecurityManager").invoke(null); if (securityManager != null) { - securityManager.getClass() + Class.forName("java.lang.SecurityManager") .getMethod("checkPermission", Permission.class) - .invoke(securityManager, new RuntimePermission("getInstrumentation")); + .invoke(securityManager, new RuntimePermission("net.bytebuddy.agent.getInstrumentation")); } } catch (NoSuchMethodException ignored) { /* security manager not available on current VM */ + } catch (ClassNotFoundException ignored) { + /* security manager not available on current VM */ } catch (InvocationTargetException exception) { - Throwable cause = exception.getCause(); + Throwable cause = exception.getTargetException(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else { @@ -90,7 +95,7 @@ } /** - * Allows the installation of this agent via the Attach API. + * Allows the installation of this agent via the attach API. * * @param arguments The unused agent arguments. * @param instrumentation The instrumentation instance. diff -Nru byte-buddy-1.11.4/byte-buddy-agent/src/main/java/net/bytebuddy/agent/package-info.java byte-buddy-1.12.21/byte-buddy-agent/src/main/java/net/bytebuddy/agent/package-info.java --- byte-buddy-1.11.4/byte-buddy-agent/src/main/java/net/bytebuddy/agent/package-info.java 2021-06-19 21:31:07.000000000 +0000 +++ byte-buddy-1.12.21/byte-buddy-agent/src/main/java/net/bytebuddy/agent/package-info.java 2023-01-04 22:45:00.000000000 +0000 @@ -16,4 +16,7 @@ /** * The Byte Buddy agent allows the redefinition of classes at runtime. */ +@NeverNull.ByDefault package net.bytebuddy.agent; + +import net.bytebuddy.agent.utility.nullability.NeverNull; diff -Nru byte-buddy-1.11.4/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/AlwaysNull.java byte-buddy-1.12.21/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/AlwaysNull.java --- byte-buddy-1.11.4/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/AlwaysNull.java 1970-01-01 00:00:00.000000000 +0000 +++ byte-buddy-1.12.21/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/AlwaysNull.java 2023-01-04 22:45:00.000000000 +0000 @@ -0,0 +1,33 @@ +/* + * 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.agent.utility.nullability; + +import javax.annotation.Nonnull; +import javax.annotation.meta.TypeQualifierNickname; +import javax.annotation.meta.When; +import java.lang.annotation.*; + +/** + * Indicates that a field, method or parameter can only be {@code null}. + */ +@Documented +@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Nonnull(when = When.NEVER) +@TypeQualifierNickname +public @interface AlwaysNull { + /* empty */ +} diff -Nru byte-buddy-1.11.4/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/MaybeNull.java byte-buddy-1.12.21/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/MaybeNull.java --- byte-buddy-1.11.4/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/MaybeNull.java 1970-01-01 00:00:00.000000000 +0000 +++ byte-buddy-1.12.21/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/MaybeNull.java 2023-01-04 22:45:00.000000000 +0000 @@ -0,0 +1,33 @@ +/* + * 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.agent.utility.nullability; + +import javax.annotation.Nonnull; +import javax.annotation.meta.TypeQualifierNickname; +import javax.annotation.meta.When; +import java.lang.annotation.*; + +/** + * Indicates that a field, method or parameter can sometimes be {@code null}. + */ +@Documented +@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Nonnull(when = When.MAYBE) +@TypeQualifierNickname +public @interface MaybeNull { + /* empty */ +} diff -Nru byte-buddy-1.11.4/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/NeverNull.java byte-buddy-1.12.21/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/NeverNull.java --- byte-buddy-1.11.4/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/NeverNull.java 1970-01-01 00:00:00.000000000 +0000 +++ byte-buddy-1.12.21/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/NeverNull.java 2023-01-04 22:45:00.000000000 +0000 @@ -0,0 +1,45 @@ +/* + * 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.agent.utility.nullability; + +import javax.annotation.Nonnull; +import javax.annotation.meta.TypeQualifierDefault; +import javax.annotation.meta.TypeQualifierNickname; +import java.lang.annotation.*; + +/** + * Indicates that a field, method or parameter can never be {@code null}. Typically, this does not need to + * be declared explicitly but is guaranteed by {@link ByDefault}. + */ +@Documented +@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Nonnull +@TypeQualifierNickname +public @interface NeverNull { + + /** + * Indicates that any field, method return or method and constructor parameter of a package is never {@code null}. + */ + @Documented + @Target(ElementType.PACKAGE) + @Retention(RetentionPolicy.RUNTIME) + @Nonnull + @TypeQualifierDefault({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) + @interface ByDefault { + /* empty */ + } +} diff -Nru byte-buddy-1.11.4/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/package-info.java byte-buddy-1.12.21/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/package-info.java --- byte-buddy-1.11.4/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ byte-buddy-1.12.21/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/package-info.java 2023-01-04 22:45:00.000000000 +0000 @@ -0,0 +1,19 @@ +/* + * 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. + */ +/** + * A package to contain nullability annotations to be used within the Byte Buddy agent project. + */ +package net.bytebuddy.agent.utility.nullability; diff -Nru byte-buddy-1.11.4/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/UnknownNull.java byte-buddy-1.12.21/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/UnknownNull.java --- byte-buddy-1.11.4/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/UnknownNull.java 1970-01-01 00:00:00.000000000 +0000 +++ byte-buddy-1.12.21/byte-buddy-agent/src/main/java/net/bytebuddy/agent/utility/nullability/UnknownNull.java 2023-01-04 22:45:00.000000000 +0000 @@ -0,0 +1,33 @@ +/* + * 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.agent.utility.nullability; + +import javax.annotation.Nonnull; +import javax.annotation.meta.TypeQualifierNickname; +import javax.annotation.meta.When; +import java.lang.annotation.*; + +/** + * Indicates that a field, method or parameter is undefined for its usage {@code null}. + */ +@Documented +@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Nonnull(when = When.UNKNOWN) +@TypeQualifierNickname +public @interface UnknownNull { + /* empty */ +} diff -Nru byte-buddy-1.11.4/byte-buddy-agent/src/main/java/net/bytebuddy/agent/VirtualMachine.java byte-buddy-1.12.21/byte-buddy-agent/src/main/java/net/bytebuddy/agent/VirtualMachine.java --- byte-buddy-1.11.4/byte-buddy-agent/src/main/java/net/bytebuddy/agent/VirtualMachine.java 2021-06-19 21:31:07.000000000 +0000 +++ byte-buddy-1.12.21/byte-buddy-agent/src/main/java/net/bytebuddy/agent/VirtualMachine.java 2023-01-04 22:45:00.000000000 +0000 @@ -21,6 +21,8 @@ import com.sun.jna.win32.StdCallLibrary; import com.sun.jna.win32.W32APIOptions; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import net.bytebuddy.agent.utility.nullability.MaybeNull; +import net.bytebuddy.agent.utility.nullability.UnknownNull; import java.io.*; import java.net.ServerSocket; @@ -76,7 +78,7 @@ * @param argument The argument to provide or {@code null} if no argument should be provided. * @throws IOException If an I/O exception occurs. */ - void loadAgent(String jarFile, String argument) throws IOException; + void loadAgent(String jarFile, @MaybeNull String argument) throws IOException; /** * Loads a native agent into the represented virtual machine. @@ -93,7 +95,7 @@ * @param argument The argument to provide or {@code null} if no argument should be provided. * @throws IOException If an I/O exception occurs. */ - void loadAgentPath(String path, String argument) throws IOException; + void loadAgentPath(String path, @MaybeNull String argument) throws IOException; /** * Loads a native agent library into the represented virtual machine. @@ -110,7 +112,7 @@ * @param argument The argument to provide or {@code null} if no argument should be provided. * @throws IOException If an I/O exception occurs. */ - void loadAgentLibrary(String library, String argument) throws IOException; + void loadAgentLibrary(String library, @MaybeNull String argument) throws IOException; /** * Starts a JMX management agent. @@ -331,21 +333,21 @@ /** * {@inheritDoc} */ - public void loadAgent(String jarFile, String argument) throws IOException { + public void loadAgent(String jarFile, @MaybeNull String argument) throws IOException { load(jarFile, false, argument); } /** * {@inheritDoc} */ - public void loadAgentPath(String path, String argument) throws IOException { + public void loadAgentPath(String path, @MaybeNull String argument) throws IOException { load(path, true, argument); } /** * {@inheritDoc} */ - public void loadAgentLibrary(String library, String argument) throws IOException { + public void loadAgentLibrary(String library, @MaybeNull String argument) throws IOException { load(library, false, argument); } @@ -357,7 +359,7 @@ * @param argument The argument to the agent or {@code null} if no argument is given. * @throws IOException If an I/O exception occurs. */ - protected void load(String file, boolean absolute, String argument) throws IOException { + protected void load(String file, boolean absolute, @MaybeNull String argument) throws IOException { Connection.Response response = connection.execute(PROTOCOL_VERSION, LOAD_COMMAND, INSTRUMENT_COMMAND, Boolean.toString(absolute), (argument == null ? file : file + ARGUMENT_DELIMITER + argument)); @@ -931,7 +933,7 @@ /** * Reads a configuration dependant variable into a memory segment. * - * @param name The name of the variable. + * @param name The name of the variable. * @param buffer The buffer to read the variable into. * @param length The length of the buffer. * @return The amount of bytes written to the buffer. @@ -1129,14 +1131,15 @@ * @param threadId A pointer to the thread id or {@code null} if no thread reference is set. * @return A handle to the created remote thread or {@code null} if the creation failed. */ + @MaybeNull @SuppressWarnings("checkstyle:methodname") WinNT.HANDLE CreateRemoteThread(WinNT.HANDLE process, - WinBase.SECURITY_ATTRIBUTES securityAttributes, + @MaybeNull WinBase.SECURITY_ATTRIBUTES securityAttributes, int stackSize, Pointer code, Pointer argument, - WinDef.DWORD creationFlags, - Pointer threadId); + @MaybeNull WinDef.DWORD creationFlags, + @MaybeNull Pointer threadId); /** * Receives the exit code of a given thread. @@ -1160,6 +1163,7 @@ * @param process A handle to the target process. * @return A pointer to the allocated code or {@code null} if the code could not be allocated. */ + @MaybeNull @SuppressWarnings("checkstyle:methodname") WinDef.LPVOID allocate_remote_code(WinNT.HANDLE process); @@ -1174,13 +1178,14 @@ * @param argument3 The forth argument or {@code null} if no such argument is provided. * @return A pointer to the allocated argument or {@code null} if the argument could not be allocated. */ + @MaybeNull @SuppressWarnings("checkstyle:methodname") WinDef.LPVOID allocate_remote_argument(WinNT.HANDLE process, String pipe, - String argument0, - String argument1, - String argument2, - String argument3); + @MaybeNull String argument0, + @MaybeNull String argument1, + @MaybeNull String argument2, + @MaybeNull String argument3); } /** @@ -1438,6 +1443,7 @@ /** * A pointer to the operation argument. */ + @MaybeNull public Pointer dataPointer; /** @@ -1448,6 +1454,7 @@ /** * A pointer to the operation descriptor. */ + @MaybeNull public Pointer descriptorPointer; /** @@ -1458,6 +1465,7 @@ /** * A pointer to the operation result. */ + @UnknownNull public Pointer resultPointer; /** @@ -1566,6 +1574,11 @@ private static final String IBM_TEMPORARY_FOLDER = "com.ibm.tools.attach.directory"; /** + * A secure random for generating randomized ids. + */ + private static final SecureRandom SECURE_RANDOM = new SecureRandom(); + + /** * The socket on which this VM and the target VM communicate. */ private final Socket socket; @@ -1602,7 +1615,7 @@ * @throws IOException If an IO exception occurs during establishing the connection. */ public static VirtualMachine attach(String processId, int timeout, Dispatcher dispatcher) throws IOException { - File directory = new File(System.getProperty(IBM_TEMPORARY_FOLDER, dispatcher.getTemporaryFolder()), ".com_ibm_tools_attach"); + File directory = new File(System.getProperty(IBM_TEMPORARY_FOLDER, dispatcher.getTemporaryFolder(processId)), ".com_ibm_tools_attach"); RandomAccessFile attachLock = new RandomAccessFile(new File(directory, "_attachlock"), "rw"); try { FileLock attachLockLock = attachLock.getChannel().lock(); @@ -1677,7 +1690,10 @@ try { serverSocket.setSoTimeout(timeout); File receiver = new File(directory, target.getProperty("vmId")); - String key = Long.toHexString(new SecureRandom().nextLong()); + String key; + synchronized (SECURE_RANDOM) { + key = Long.toHexString(SECURE_RANDOM.nextLong()); + } File reply = new File(receiver, "replyInfo"); try { if (reply.createNewFile()) { @@ -1787,7 +1803,7 @@ /** * {@inheritDoc} */ - public void loadAgent(String jarFile, String argument) throws IOException { + public void loadAgent(String jarFile, @MaybeNull String argument) throws IOException { write(socket, ("ATTACH_LOADAGENT(instrument," + jarFile + '=' + (argument == null ? "" : argument) + ')').getBytes("UTF-8")); String answer = new String(read(socket), "UTF-8"); if (answer.startsWith("ATTACH_ERR")) { @@ -1800,7 +1816,7 @@ /** * {@inheritDoc} */ - public void loadAgentPath(String path, String argument) throws IOException { + public void loadAgentPath(String path, @MaybeNull String argument) throws IOException { write(socket, ("ATTACH_LOADAGENTPATH(" + path + (argument == null ? "" : (',' + argument)) + ')').getBytes("UTF-8")); String answer = new String(read(socket), "UTF-8"); if (answer.startsWith("ATTACH_ERR")) { @@ -1813,7 +1829,7 @@ /** * {@inheritDoc} */ - public void loadAgentLibrary(String library, String argument) throws IOException { + public void loadAgentLibrary(String library, @MaybeNull String argument) throws IOException { write(socket, ("ATTACH_LOADAGENTLIBRARY(" + library + (argument == null ? "" : (',' + argument)) + ')').getBytes("UTF-8")); String answer = new String(read(socket), "UTF-8"); if (answer.startsWith("ATTACH_ERR")) { @@ -1911,9 +1927,10 @@ /** * Returns this machine's temporary folder. * + * @param processId The target process's id. * @return The temporary folder. */ - String getTemporaryFolder(); + String getTemporaryFolder(String processId); /** * Returns the process id of this process. @@ -2016,7 +2033,13 @@ /** * {@inheritDoc} */ - public String getTemporaryFolder() { + public String getTemporaryFolder(String processId) { + if (Platform.isLinux()) { + File file = new File("/proc/" + processId + "/root/tmp"); + if (file.isDirectory() && file.canRead()) { + return file.getAbsolutePath(); + } + } String temporaryFolder = System.getenv("TMPDIR"); return temporaryFolder == null ? "/tmp" : temporaryFolder; } @@ -2050,8 +2073,10 @@ try { // The binding for 'stat' is very platform dependant. To avoid the complexity of binding the correct method, // stat is called as a separate command. This is less efficient but more portable. - String statUserSwitch = Platform.isMac() ? "-f" : "-c"; - Process process = Runtime.getRuntime().exec("stat " + statUserSwitch + " %u " + file.getAbsolutePath()); + Process process = Runtime.getRuntime().exec(new String[]{"stat", + Platform.isMac() ? "-f" : "-c", + "%u", + file.getAbsolutePath()}); int attempts = this.attempts; boolean exited = false; String line = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8")).readLine(); @@ -2124,7 +2149,7 @@ library.semop(semaphore, target, 1); } catch (LastErrorException exception) { if (acceptUnavailable && (Native.getLastError() == PosixLibrary.EAGAIN - || Native.getLastError() == PosixLibrary.EDEADLK)) { + || Native.getLastError() == PosixLibrary.EDEADLK)) { break; } else { throw exception; @@ -2299,7 +2324,7 @@ /** * {@inheritDoc} */ - public String getTemporaryFolder() { + public String getTemporaryFolder(String processId) { WinDef.DWORD length = new WinDef.DWORD(WinDef.MAX_PATH); char[] path = new char[length.intValue()]; if (Kernel32.INSTANCE.GetTempPath(length, path).intValue() == 0) { @@ -2483,6 +2508,7 @@ * @param name The semaphore's name. * @return The handle or {@code null} if the handle could not be created. */ + @MaybeNull @SuppressWarnings("checkstyle:methodname") WinNT.HANDLE OpenSemaphoreW(int access, boolean inheritHandle, String name); @@ -2495,8 +2521,12 @@ * @param name The semaphore's name. * @return The handle or {@code null} if the handle could not be created. */ + @MaybeNull @SuppressWarnings("checkstyle:methodname") - WinNT.HANDLE CreateSemaphoreW(WinBase.SECURITY_ATTRIBUTES securityAttributes, long count, long maximumCount, String name); + WinNT.HANDLE CreateSemaphoreW(@MaybeNull WinBase.SECURITY_ATTRIBUTES securityAttributes, + long count, + long maximumCount, + String name); /** * Releases the semaphore. @@ -2507,7 +2537,7 @@ * @return {@code true} if the semaphore was successfully released. */ @SuppressWarnings("checkstyle:methodname") - boolean ReleaseSemaphore(WinNT.HANDLE handle, long count, Long previousCount); + boolean ReleaseSemaphore(WinNT.HANDLE handle, long count, @MaybeNull Long previousCount); /** * Create or opens a mutex. @@ -2517,6 +2547,7 @@ * @param name The mutex name. * @return The handle to the mutex or {@code null} if the mutex could not be created. */ + @MaybeNull @SuppressWarnings("checkstyle:methodname") WinNT.HANDLE CreateMutex(SecurityAttributes attributes, boolean owner, String name); @@ -2549,11 +2580,13 @@ /** * The descriptor's length. */ + @MaybeNull public WinDef.DWORD length; /** * A pointer to the descriptor. */ + @MaybeNull public Pointer securityDescriptor; /** diff -Nru byte-buddy-1.11.4/byte-buddy-agent/src/test/java/net/bytebuddy/agent/AttacherTest.java byte-buddy-1.12.21/byte-buddy-agent/src/test/java/net/bytebuddy/agent/AttacherTest.java --- byte-buddy-1.11.4/byte-buddy-agent/src/test/java/net/bytebuddy/agent/AttacherTest.java 2021-06-19 21:31:07.000000000 +0000 +++ byte-buddy-1.12.21/byte-buddy-agent/src/test/java/net/bytebuddy/agent/AttacherTest.java 2023-01-04 22:45:00.000000000 +0000 @@ -46,7 +46,7 @@ constructor.newInstance(); fail(); } catch (InvocationTargetException exception) { - throw (Exception) exception.getCause(); + throw (Exception) exception.getTargetException(); } } diff -Nru byte-buddy-1.11.4/byte-buddy-agent/src/test/java/net/bytebuddy/agent/ByteBuddyAgentAttachmentTypeEvaluator.java byte-buddy-1.12.21/byte-buddy-agent/src/test/java/net/bytebuddy/agent/ByteBuddyAgentAttachmentTypeEvaluator.java --- byte-buddy-1.11.4/byte-buddy-agent/src/test/java/net/bytebuddy/agent/ByteBuddyAgentAttachmentTypeEvaluator.java 2021-06-19 21:31:07.000000000 +0000 +++ byte-buddy-1.12.21/byte-buddy-agent/src/test/java/net/bytebuddy/agent/ByteBuddyAgentAttachmentTypeEvaluator.java 2023-01-04 22:45:00.000000000 +0000 @@ -2,8 +2,8 @@ import org.junit.Test; -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.MatcherAssert.*; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; public class ByteBuddyAgentAttachmentTypeEvaluator { diff -Nru byte-buddy-1.11.4/byte-buddy-agent/src/test/java/net/bytebuddy/agent/ByteBuddyAgentTest.java byte-buddy-1.12.21/byte-buddy-agent/src/test/java/net/bytebuddy/agent/ByteBuddyAgentTest.java --- byte-buddy-1.11.4/byte-buddy-agent/src/test/java/net/bytebuddy/agent/ByteBuddyAgentTest.java 2021-06-19 21:31:07.000000000 +0000 +++ byte-buddy-1.12.21/byte-buddy-agent/src/test/java/net/bytebuddy/agent/ByteBuddyAgentTest.java 2023-01-04 22:45:00.000000000 +0000 @@ -16,40 +16,36 @@ public class ByteBuddyAgentTest { - private static final String INSTRUMENTATION = "instrumentation"; - - private static final Object STATIC_FIELD = null; - private Instrumentation actualInstrumentation; @Before public void setUp() throws Exception { - Field field = Installer.class.getDeclaredField(INSTRUMENTATION); + Field field = Installer.class.getDeclaredField("instrumentation"); field.setAccessible(true); - actualInstrumentation = (Instrumentation) field.get(STATIC_FIELD); + actualInstrumentation = (Instrumentation) field.get(null); } @After public void tearDown() throws Exception { - Field field = Installer.class.getDeclaredField(INSTRUMENTATION); + Field field = Installer.class.getDeclaredField("instrumentation"); field.setAccessible(true); - field.set(STATIC_FIELD, actualInstrumentation); + field.set(null, actualInstrumentation); } @Test public void testInstrumentationExtraction() throws Exception { - Field field = Installer.class.getDeclaredField(INSTRUMENTATION); + Field field = Installer.class.getDeclaredField("instrumentation"); field.setAccessible(true); Instrumentation instrumentation = mock(Instrumentation.class); - field.set(STATIC_FIELD, instrumentation); + field.set(null, instrumentation); assertThat(ByteBuddyAgent.getInstrumentation(), is(instrumentation)); } @Test(expected = IllegalStateException.class) public void testMissingInstrumentationThrowsException() throws Exception { - Field field = Installer.class.getDeclaredField(INSTRUMENTATION); + Field field = Installer.class.getDeclaredField("instrumentation"); field.setAccessible(true); - field.set(STATIC_FIELD, null); + field.set(null, null); ByteBuddyAgent.getInstrumentation(); } @@ -61,7 +57,7 @@ constructor.newInstance(); fail(); } catch (InvocationTargetException exception) { - throw (Exception) exception.getCause(); + throw (Exception) exception.getTargetException(); } } } diff -Nru byte-buddy-1.11.4/byte-buddy-agent/src/test/java/net/bytebuddy/agent/InstallerTest.java byte-buddy-1.12.21/byte-buddy-agent/src/test/java/net/bytebuddy/agent/InstallerTest.java --- byte-buddy-1.11.4/byte-buddy-agent/src/test/java/net/bytebuddy/agent/InstallerTest.java 2021-06-19 21:31:07.000000000 +0000 +++ byte-buddy-1.12.21/byte-buddy-agent/src/test/java/net/bytebuddy/agent/InstallerTest.java 2023-01-04 22:45:00.000000000 +0000 @@ -1,12 +1,12 @@ package net.bytebuddy.agent; -import net.bytebuddy.test.utility.MockitoRule; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TestRule; +import org.junit.rules.MethodRule; import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; import java.lang.instrument.Instrumentation; import java.lang.reflect.*; @@ -20,12 +20,8 @@ private static final String FOO = "foo"; - private static final String INSTRUMENTATION = "instrumentation"; - - private static final Object STATIC_FIELD = null; - @Rule - public final TestRule mockitoRule = new MockitoRule(this); + public final MethodRule mockitoRule = MockitoJUnit.rule().silent(); @Mock private Instrumentation instrumentation; @@ -34,16 +30,16 @@ @Before public void setUp() throws Exception { - Field field = Installer.class.getDeclaredField(INSTRUMENTATION); + Field field = Installer.class.getDeclaredField("instrumentation"); field.setAccessible(true); - actualInstrumentation = (Instrumentation) field.get(STATIC_FIELD); + actualInstrumentation = (Instrumentation) field.get(null); } @After public void tearDown() throws Exception { - Field field = Installer.class.getDeclaredField(INSTRUMENTATION); + Field field = Installer.class.getDeclaredField("instrumentation"); field.setAccessible(true); - field.set(STATIC_FIELD, actualInstrumentation); + field.set(null, actualInstrumentation); } @Test @@ -86,7 +82,7 @@ constructor.newInstance(); fail(); } catch (InvocationTargetException exception) { - throw (Exception) exception.getCause(); + throw (Exception) exception.getTargetException(); } } } diff -Nru byte-buddy-1.11.4/byte-buddy-agent/src/test/java/net/bytebuddy/agent/SampleAgent.java byte-buddy-1.12.21/byte-buddy-agent/src/test/java/net/bytebuddy/agent/SampleAgent.java --- byte-buddy-1.11.4/byte-buddy-agent/src/test/java/net/bytebuddy/agent/SampleAgent.java 2021-06-19 21:31:07.000000000 +0000 +++ byte-buddy-1.12.21/byte-buddy-agent/src/test/java/net/bytebuddy/agent/SampleAgent.java 2023-01-04 22:45:00.000000000 +0000 @@ -1,9 +1,9 @@ package net.bytebuddy.agent; public class SampleAgent { - + public static String argument; - + public static void agentmain(String argument) { SampleAgent.argument = argument; } diff -Nru byte-buddy-1.11.4/byte-buddy-agent/src/test/java/net/bytebuddy/agent/VirtualMachineAttachmentTest.java byte-buddy-1.12.21/byte-buddy-agent/src/test/java/net/bytebuddy/agent/VirtualMachineAttachmentTest.java --- byte-buddy-1.11.4/byte-buddy-agent/src/test/java/net/bytebuddy/agent/VirtualMachineAttachmentTest.java 2021-06-19 21:31:07.000000000 +0000 +++ byte-buddy-1.12.21/byte-buddy-agent/src/test/java/net/bytebuddy/agent/VirtualMachineAttachmentTest.java 2023-01-04 22:45:00.000000000 +0000 @@ -1,10 +1,12 @@ package net.bytebuddy.agent; import net.bytebuddy.dynamic.ClassFileLocator; -import org.hamcrest.CoreMatchers; +import net.bytebuddy.test.utility.JnaRule; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TestRule; import java.io.File; import java.io.FileOutputStream; @@ -14,15 +16,16 @@ import java.util.jar.JarOutputStream; import java.util.jar.Manifest; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.MatcherAssert.assertThat; public class VirtualMachineAttachmentTest { private static final String FOO = "foo"; + @Rule + public TestRule jnaRule = new JnaRule(); + private File agent; @Before @@ -59,7 +62,7 @@ } assertThat(SampleAgent.argument, is(FOO)); } - + @Test(timeout = 10000L) public void testSystemProperties() throws Exception { VirtualMachine virtualMachine = (VirtualMachine) VirtualMachine.Resolver.INSTANCE.run() diff -Nru byte-buddy-1.11.4/byte-buddy-agent/src/test/java/net/bytebuddy/agent/VirtualMachineForHotSpotTest.java byte-buddy-1.12.21/byte-buddy-agent/src/test/java/net/bytebuddy/agent/VirtualMachineForHotSpotTest.java --- byte-buddy-1.11.4/byte-buddy-agent/src/test/java/net/bytebuddy/agent/VirtualMachineForHotSpotTest.java 2021-06-19 21:31:07.000000000 +0000 +++ byte-buddy-1.12.21/byte-buddy-agent/src/test/java/net/bytebuddy/agent/VirtualMachineForHotSpotTest.java 2023-01-04 22:45:00.000000000 +0000 @@ -13,7 +13,7 @@ import static org.mockito.Mockito.*; public class VirtualMachineForHotSpotTest { - + private static final String FOO = "foo", BAR = "bar"; @Test diff -Nru byte-buddy-1.11.4/byte-buddy-agent/src/test/java/net/bytebuddy/agent/VirtualMachineForOpenJ9Test.java byte-buddy-1.12.21/byte-buddy-agent/src/test/java/net/bytebuddy/agent/VirtualMachineForOpenJ9Test.java --- byte-buddy-1.11.4/byte-buddy-agent/src/test/java/net/bytebuddy/agent/VirtualMachineForOpenJ9Test.java 2021-06-19 21:31:07.000000000 +0000 +++ byte-buddy-1.12.21/byte-buddy-agent/src/test/java/net/bytebuddy/agent/VirtualMachineForOpenJ9Test.java 2023-01-04 22:45:00.000000000 +0000 @@ -57,11 +57,12 @@ } @Test(timeout = 10000L) - @JavaVersionRule.Enforce(7) // Fails sometimes on Java 6 due to timeout issues that are difficult to reproduce and solve. + @JavaVersionRule.Enforce(7) + // Fails sometimes on Java 6 due to timeout issues that are difficult to reproduce and solve. public void testAttachment() throws Throwable { final AtomicReference+ * Warms up the generated {@link ClassFileTransformer} to trigger class loading of classes used by the transformer + * prior to its actual use. Ideally, warmup should include classes that cause a transformation and classes that + * are ignored. Warming up can be especially useful when transforming classes on the boot path, where circularity + * errors are more likely. At the same time, warming up might load classes that are expected to be unloaded + * when this agent is installed. + *
+ *+ * Important: Warming up is applied just as a regular transformation and will also invoke the {@link Listener}. + * This is done to avoid that listener classes can cause circularities. It is the users responsibility to suppress + * such log output, if necessary. + *
+ * + * @param type The types to include in the warmup. + * @return A new agent builder that considers the supplied classes in its warmup. + */ + AgentBuilder warmUp(Class>... type); + + /** + *+ * Warms up the generated {@link ClassFileTransformer} to trigger class loading of classes used by the transformer + * prior to its actual use. Ideally, warmup should include classes that cause a transformation and classes that + * are ignored. Warming up can be especially useful when transforming classes on the boot path, where circularity + * errors are more likely. At the same time, warming up might load classes that are expected to be unloaded + * when this agent is installed. + *
+ *+ * Important: Warming up is applied just as a regular transformation and will also invoke the {@link Listener}. + * This is done to avoid that listener classes can cause circularities. It is the users responsibility to suppress + * such log output, if necessary. + *
+ * + * @param types The types to include in the warmup. + * @return A new agent builder that considers the supplied classes in its warmup. + */ + AgentBuilder warmUp(Collection* In order to assure the correct handling of the {@link InstallationListener}, an uninstallation should be applied @@ -685,9 +721,28 @@ /** *
* Creates and installs a {@link ResettableClassFileTransformer} that implements the configuration of + * this agent builder with a given {@link java.lang.instrument.Instrumentation}. If retransformation is enabled, + * the installation also causes all loaded types to be retransformed which have changed compared to the previous + * class file transformer that is provided as an argument. + *
+ *+ * In order to assure the correct handling of the {@link InstallationListener}, an uninstallation should be applied + * via the {@link ResettableClassFileTransformer}'s {@code reset} methods. + *
+ * + * @param instrumentation The instrumentation on which this agent builder's configuration is to be installed. + * @param classFileTransformer The class file transformer that is being patched. + * @param patchMode The patch mode to apply. + * @return The installed class file transformer. + */ + ResettableClassFileTransformer patchOn(Instrumentation instrumentation, ResettableClassFileTransformer classFileTransformer, PatchMode patchMode); + + /** + *+ * Creates and installs a {@link ResettableClassFileTransformer} that implements the configuration of * this agent builder with the Byte Buddy-agent which must be installed prior to calling this method. If retransformation * is enabled, the installation also causes all loaded types to be retransformed which have changed compared to the previous - * class file transformer that is provided as an argument. + * class file transformer that is provided as an argument. Without specification, {@link PatchMode#OVERLAP} is used. *
** In order to assure the correct handling of the {@link InstallationListener}, an uninstallation should be applied @@ -701,6 +756,25 @@ ResettableClassFileTransformer patchOnByteBuddyAgent(ResettableClassFileTransformer classFileTransformer); /** + *
+ * Creates and installs a {@link ResettableClassFileTransformer} that implements the configuration of + * this agent builder with the Byte Buddy-agent which must be installed prior to calling this method. If retransformation + * is enabled, the installation also causes all loaded types to be retransformed which have changed compared to the previous + * class file transformer that is provided as an argument. + *
+ *+ * In order to assure the correct handling of the {@link InstallationListener}, an uninstallation should be applied + * via the {@link ResettableClassFileTransformer}'s {@code reset} methods. + *
+ * + * @param classFileTransformer The class file transformer that is being patched. + * @param patchMode The patch mode to apply. + * @return The installed class file transformer. + * @see AgentBuilder#patchOn(Instrumentation, ResettableClassFileTransformer, PatchMode) + */ + ResettableClassFileTransformer patchOnByteBuddyAgent(ResettableClassFileTransformer classFileTransformer, PatchMode patchMode); + + /** * An abstraction for extending a matcher. * * @param
@@ -3134,14 +3228,14 @@
/**
* {@inheritDoc}
*/
- public TypePool typePool(ClassFileLocator classFileLocator, ClassLoader classLoader) {
+ public TypePool typePool(ClassFileLocator classFileLocator, @MaybeNull ClassLoader classLoader) {
return new TypePool.Default.WithLazyResolution(TypePool.CacheProvider.Simple.withObjectType(), classFileLocator, readerMode);
}
/**
* {@inheritDoc}
*/
- public TypePool typePool(ClassFileLocator classFileLocator, ClassLoader classLoader, String name) {
+ public TypePool typePool(ClassFileLocator classFileLocator, @MaybeNull ClassLoader classLoader, String name) {
return typePool(classFileLocator, classLoader);
}
}
@@ -3190,14 +3284,14 @@
/**
* {@inheritDoc}
*/
- public TypePool typePool(ClassFileLocator classFileLocator, ClassLoader classLoader) {
+ public TypePool typePool(ClassFileLocator classFileLocator, @MaybeNull ClassLoader classLoader) {
return new TypePool.Default(TypePool.CacheProvider.Simple.withObjectType(), classFileLocator, readerMode);
}
/**
* {@inheritDoc}
*/
- public TypePool typePool(ClassFileLocator classFileLocator, ClassLoader classLoader, String name) {
+ public TypePool typePool(ClassFileLocator classFileLocator, @MaybeNull ClassLoader classLoader, String name) {
return typePool(classFileLocator, classLoader);
}
}
@@ -3247,14 +3341,14 @@
/**
* {@inheritDoc}
*/
- public TypePool typePool(ClassFileLocator classFileLocator, ClassLoader classLoader) {
+ public TypePool typePool(ClassFileLocator classFileLocator, @MaybeNull ClassLoader classLoader) {
return TypePool.ClassLoading.of(classLoader, new TypePool.Default.WithLazyResolution(TypePool.CacheProvider.Simple.withObjectType(), classFileLocator, readerMode));
}
/**
* {@inheritDoc}
*/
- public TypePool typePool(ClassFileLocator classFileLocator, ClassLoader classLoader, String name) {
+ public TypePool typePool(ClassFileLocator classFileLocator, @MaybeNull ClassLoader classLoader, String name) {
return typePool(classFileLocator, classLoader);
}
}
@@ -3290,14 +3384,14 @@
/**
* {@inheritDoc}
*/
- public TypePool typePool(ClassFileLocator classFileLocator, ClassLoader classLoader) {
+ public TypePool typePool(ClassFileLocator classFileLocator, @MaybeNull ClassLoader classLoader) {
return new TypePool.Default.WithLazyResolution(locate(classLoader), classFileLocator, readerMode);
}
/**
* {@inheritDoc}
*/
- public TypePool typePool(ClassFileLocator classFileLocator, ClassLoader classLoader, String name) {
+ public TypePool typePool(ClassFileLocator classFileLocator, @MaybeNull ClassLoader classLoader, String name) {
return new TypePool.Default.WithLazyResolution(new TypePool.CacheProvider.Discriminating(ElementMatchers.
* Note: When applying a redefinition, it is normally required to use a {@link TypeStrategy} that applies
* a redefinition instead of rebasing classes such as {@link TypeStrategy.Default#REDEFINE}. Also, consider
- * the constrains given by this type strategy.
+ * the constraints given by this type strategy.
*
* Note: When applying a retransformation, it is normally required to use a {@link TypeStrategy} that applies
* a redefinition instead of rebasing classes such as {@link TypeStrategy.Default#REDEFINE}. Also, consider
- * the constrains given by this type strategy.
+ * the constraints given by this type strategy.
*
+ * A discovery strategy that simplifies the application of {@link Reiterating} by assuming that the
+ * loaded classes that are returned by {@link Instrumentation#getAllLoadedClasses()} are always
+ * returned in the same order.
+ *
+ * Important: While this increases the performance of reiteration, it relies on an implementation
+ * detail of the JVM. Also, this strategy does not consider the possibility of classes being unloaded
+ * during reiteration. For these reasons, this strategy has to be used with care!
+ *
* Implements the instrumentation of the {@code LambdaMetafactory} if this feature is enabled.
+ *
+ * Warning: This feature is not recommended for production systems but only for experiments or debugging
+ * purposes. It might no longer work in a future release and makes assumptions over JVM-internal API.
+ *
+ * A post processor for advice methods that is invoked after advice is executed. A post processor
+ * is invoked after the instrumented method and only after a regular completion of the method. When
+ * invoked, the advice method's return value is stored in the local variable array. Upon completion,
+ * the local variable array must still be intact and the stack must be empty. A frame is added
+ * subsequently to the post processor's execution, making it feasible to add a jump instruction to the
+ * end of the method after which no further byte code instructions must be issued. This also applies
+ * to compound post processors. If a post processor emits a frame as its last instruction, it should
+ * yield a NOP instruction to avoid that subsequent code starts with a frame.
+ *
+ * Important: A post processor is triggered after the suppression handler. Exceptions triggered
+ * by post processing code will therefore cause those exceptions to be propagated unless the post
+ * processor configures explicit exception handling.
+ *
+ * The code's preamble is adjusted for the alternative metafactory to ressemble the following:
+ *
+ * public static CallSite metafactory(MethodHandles.Lookup caller,
+ * String interfaceMethodName,
+ * MethodType factoryType,
+ * MethodType interfaceMethodType,
+ * MethodHandle implementation,
+ * MethodType dynamicMethodType) throws Exception {
+ * boolean serializable = false;
+ * {@code List
*/
- @HashCodeAndEqualsPlugin.Enhance
- protected static class LambdaInstanceFactory {
+ protected enum LambdaMetafactoryFactory implements ByteCodeAppender {
/**
- * The name of a factory for a lambda expression.
+ * Implements the {@code java.lang.invoke.LambdaMetafactory#metafactory} method.
*/
- private static final String LAMBDA_FACTORY = "get$Lambda";
+ REGULAR(6, 11) {
+ @Override
+ protected void onDispatch(MethodVisitor methodVisitor) {
+ methodVisitor.visitInsn(Opcodes.ICONST_0);
+ methodVisitor.visitVarInsn(Opcodes.ISTORE, 6);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Collections", "emptyList", "()Ljava/util/List;", false);
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 7);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Collections", "emptyList", "()Ljava/util/List;", false);
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 8);
+ methodVisitor.visitFrame(Opcodes.F_APPEND, 3, new Object[]{Opcodes.INTEGER, "java/util/List", "java/util/List"}, 0, null);
+ }
+ },
/**
- * A prefix for a field that represents a property of a lambda expression.
+ * Implements the {@code java.lang.invoke.LambdaMetafactory#altMetafactory} method.
*/
- private static final String FIELD_PREFIX = "arg$";
+ ALTERNATIVE(6, 16) {
+ @Override
+ protected void onDispatch(MethodVisitor methodVisitor) {
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
+ methodVisitor.visitInsn(Opcodes.ICONST_3);
+ methodVisitor.visitInsn(Opcodes.AALOAD);
+ methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Integer");
+ methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
+ methodVisitor.visitVarInsn(Opcodes.ISTORE, 4);
+ methodVisitor.visitInsn(Opcodes.ICONST_4);
+ methodVisitor.visitVarInsn(Opcodes.ISTORE, 5);
+ methodVisitor.visitVarInsn(Opcodes.ILOAD, 4);
+ methodVisitor.visitInsn(Opcodes.ICONST_2);
+ methodVisitor.visitInsn(Opcodes.IAND);
+ Label first = new Label();
+ methodVisitor.visitJumpInsn(Opcodes.IFEQ, first);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
+ methodVisitor.visitVarInsn(Opcodes.ILOAD, 5);
+ methodVisitor.visitIincInsn(5, 1);
+ methodVisitor.visitInsn(Opcodes.AALOAD);
+ methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Integer");
+ methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
+ methodVisitor.visitVarInsn(Opcodes.ISTORE, 7);
+ methodVisitor.visitVarInsn(Opcodes.ILOAD, 7);
+ methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 6);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
+ methodVisitor.visitVarInsn(Opcodes.ILOAD, 5);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 6);
+ methodVisitor.visitInsn(Opcodes.ICONST_0);
+ methodVisitor.visitVarInsn(Opcodes.ILOAD, 7);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V", false);
+ methodVisitor.visitVarInsn(Opcodes.ILOAD, 5);
+ methodVisitor.visitVarInsn(Opcodes.ILOAD, 7);
+ methodVisitor.visitInsn(Opcodes.IADD);
+ methodVisitor.visitVarInsn(Opcodes.ISTORE, 5);
+ Label second = new Label();
+ methodVisitor.visitJumpInsn(Opcodes.GOTO, second);
+ methodVisitor.visitLabel(first);
+ methodVisitor.visitFrame(Opcodes.F_APPEND, 2, new Object[]{Opcodes.INTEGER, Opcodes.INTEGER}, 0, null);
+ methodVisitor.visitInsn(Opcodes.ICONST_0);
+ methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 6);
+ methodVisitor.visitLabel(second);
+ methodVisitor.visitFrame(Opcodes.F_APPEND, 1, new Object[]{"[Ljava/lang/Class;"}, 0, null);
+ methodVisitor.visitVarInsn(Opcodes.ILOAD, 4);
+ methodVisitor.visitInsn(Opcodes.ICONST_2);
+ methodVisitor.visitInsn(Opcodes.IAND);
+ Label third = new Label();
+ methodVisitor.visitJumpInsn(Opcodes.IFEQ, third);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
+ methodVisitor.visitVarInsn(Opcodes.ILOAD, 5);
+ methodVisitor.visitIincInsn(5, 1);
+ methodVisitor.visitInsn(Opcodes.AALOAD);
+ methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Integer");
+ methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
+ methodVisitor.visitVarInsn(Opcodes.ISTORE, 8);
+ methodVisitor.visitVarInsn(Opcodes.ILOAD, 8);
+ methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/invoke/MethodType");
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 7);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
+ methodVisitor.visitVarInsn(Opcodes.ILOAD, 5);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 7);
+ methodVisitor.visitInsn(Opcodes.ICONST_0);
+ methodVisitor.visitVarInsn(Opcodes.ILOAD, 8);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V", false);
+ Label forth = new Label();
+ methodVisitor.visitJumpInsn(Opcodes.GOTO, forth);
+ methodVisitor.visitLabel(third);
+ methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+ methodVisitor.visitInsn(Opcodes.ICONST_0);
+ methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/invoke/MethodType");
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 7);
+ methodVisitor.visitLabel(forth);
+ methodVisitor.visitFrame(Opcodes.F_APPEND, 1, new Object[]{"[Ljava/lang/invoke/MethodType;"}, 0, null);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
+ methodVisitor.visitInsn(Opcodes.ICONST_0);
+ methodVisitor.visitInsn(Opcodes.AALOAD);
+ methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/invoke/MethodType");
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 8);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
+ methodVisitor.visitInsn(Opcodes.ICONST_1);
+ methodVisitor.visitInsn(Opcodes.AALOAD);
+ methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/invoke/MethodHandle");
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 9);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
+ methodVisitor.visitInsn(Opcodes.ICONST_2);
+ methodVisitor.visitInsn(Opcodes.AALOAD);
+ methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/invoke/MethodType");
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 10);
+ methodVisitor.visitVarInsn(Opcodes.ILOAD, 4);
+ methodVisitor.visitInsn(Opcodes.ICONST_1);
+ methodVisitor.visitInsn(Opcodes.IAND);
+ Label fifth = new Label();
+ methodVisitor.visitJumpInsn(Opcodes.IFEQ, fifth);
+ methodVisitor.visitInsn(Opcodes.ICONST_1);
+ Label sixth = new Label();
+ methodVisitor.visitJumpInsn(Opcodes.GOTO, sixth);
+ methodVisitor.visitLabel(fifth);
+ methodVisitor.visitFrame(Opcodes.F_APPEND, 3, new Object[]{"java/lang/invoke/MethodType", "java/lang/invoke/MethodHandle", "java/lang/invoke/MethodType"}, 0, null);
+ methodVisitor.visitInsn(Opcodes.ICONST_0);
+ methodVisitor.visitLabel(sixth);
+ methodVisitor.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{Opcodes.INTEGER});
+ methodVisitor.visitVarInsn(Opcodes.ISTORE, 11);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 6);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Arrays", "asList", "([Ljava/lang/Object;)Ljava/util/List;", false);
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 12);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 7);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Arrays", "asList", "([Ljava/lang/Object;)Ljava/util/List;", false);
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 13);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 8);
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 3);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 9);
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 4);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 10);
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 5);
+ methodVisitor.visitVarInsn(Opcodes.ILOAD, 11);
+ methodVisitor.visitVarInsn(Opcodes.ISTORE, 6);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 12);
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 7);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 13);
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 8);
+ methodVisitor.visitFrame(Opcodes.F_FULL, 9, new Object[]{"java/lang/invoke/MethodHandles$Lookup",
+ "java/lang/String",
+ "java/lang/invoke/MethodType",
+ "java/lang/invoke/MethodType",
+ "java/lang/invoke/MethodHandle",
+ "java/lang/invoke/MethodType",
+ Opcodes.INTEGER,
+ "java/util/List",
+ "java/util/List"}, 0, null);
+ }
+ };
/**
- * The infix to use for naming classes that represent lambda expression. The additional prefix
- * is necessary because the subsequent counter is not sufficient to keep names unique compared
- * to the original factory.
+ * A loader for the generated lambda class.
*/
- private static final String LAMBDA_TYPE_INFIX = "$$Lambda$ByteBuddy$";
+ private static final Loader LOADER = resolve();
/**
- * A type-safe constant to express that a class is not already loaded when applying a class file transformer.
+ * Resolves the loader for the current VM.
+ *
+ * @return An appropriate loader.
*/
- private static final Class> NOT_PREVIOUSLY_DEFINED = null;
+ @SuppressFBWarnings(value = {"DE_MIGHT_IGNORE", "REC_CATCH_EXCEPTION"}, justification = "Exception should not be rethrown but trigger a fallback.")
+ private static Loader resolve() {
+ try {
+ Class> type = Class.forName("java.lang.invoke.MethodHandles$Lookup", false, null);
+ type.getMethod("defineHiddenClass",
+ byte[].class,
+ boolean.class,
+ Class.forName("[Ljava.lang.invoke.MethodHandles$Lookup$ClassOption;", false, null));
+ type.getMethod("defineHiddenClassWithClassData",
+ byte[].class,
+ Object.class,
+ boolean.class,
+ Class.forName("[Ljava.lang.invoke.MethodHandles$Lookup$ClassOption;", false, null));
+ return Loader.UsingMethodHandleLookup.INSTANCE;
+ } catch (Exception ignored) {
+ /* do nothing */
+ }
+ for (Loader.UsingUnsafe loader : Loader.UsingUnsafe.values()) {
+ try {
+ Class.forName(loader.getType().replace('/', '.'),
+ false,
+ null).getMethod("defineAnonymousClass", Class.class, byte[].class, Object[].class);
+ return loader;
+ } catch (Exception ignored) {
+ /* do nothing */
+ }
+ }
+ return Loader.Unavailable.INSTANCE;
+ }
/**
- * A counter for naming lambda expressions randomly.
+ * The required stack size for this factory.
*/
- private static final AtomicInteger LAMBDA_NAME_COUNTER = new AtomicInteger();
+ private final int stackSize;
/**
- * The Byte Buddy instance to use for creating lambda objects.
+ * The required local variable length for this factory.
*/
- private final ByteBuddy byteBuddy;
+ private final int localVariableLength;
/**
- * Creates a new lambda instance factory.
+ * Creates a new factory.
*
- * @param byteBuddy The Byte Buddy instance to use for creating lambda objects.
+ * @param stackSize The required stack size for this factory.
+ * @param localVariableLength The required local variable length for this factory.
*/
- protected LambdaInstanceFactory(ByteBuddy byteBuddy) {
- this.byteBuddy = byteBuddy;
+ LambdaMetafactoryFactory(int stackSize, int localVariableLength) {
+ this.stackSize = stackSize;
+ this.localVariableLength = localVariableLength;
}
/**
- * Applies this lambda meta factory.
- *
- * @param targetTypeLookup A lookup context representing the creating class of this lambda expression.
- * @param lambdaMethodName The name of the lambda expression's represented method.
- * @param factoryMethodType The type of the lambda expression's represented method.
- * @param lambdaMethodType The type of the lambda expression's factory method.
- * @param targetMethodHandle A handle representing the target of the lambda expression's method.
- * @param specializedLambdaMethodType A specialization of the type of the lambda expression's represented method.
- * @param serializable {@code true} if the lambda expression should be serializable.
- * @param markerInterfaces A list of interfaces for the lambda expression to represent.
- * @param additionalBridges A list of additional bridge methods to be implemented by the lambda expression.
- * @param classFileTransformers A collection of class file transformers to apply when creating the class.
- * @return A binary representation of the transformed class file.
+ * {@inheritDoc}
*/
- public byte[] make(Object targetTypeLookup,
- String lambdaMethodName,
- Object factoryMethodType,
- Object lambdaMethodType,
- Object targetMethodHandle,
- Object specializedLambdaMethodType,
- boolean serializable,
- List
+ * public static CallSite altMetafactory(MethodHandles.Lookup caller,
+ * String interfaceMethodName,
+ * MethodType factoryType,
+ * Object... argument) throws Exception {
+ * int flags = (Integer) argument[3];
+ * int index = 4;
+ * {@code Class>[]} markerInterface;
+ * if ((flags{@code &} 2) != 0) {
+ * int count = (Integer) argument[index++];
+ * markerInterface = new{@code Class>}[count];
+ * System.arraycopy(argument, index, markerInterface, 0, count);
+ * index += count;
+ * } else {
+ * markerInterface = new{@code Class>}[0];
+ * }
+ * MethodType[] additionalBridge;
+ * if ((flags{@code &} 2) != 0) {
+ * int count = (Integer) argument[index++];
+ * additionalBridge = new MethodType[count];
+ * System.arraycopy(argument, index, additionalBridge, 0, count);
+ * } else {
+ * additionalBridge = new MethodType[0];
+ * }
+ * MethodType interfaceMethodType = (MethodType) argument[0];
+ * MethodHandle implementation = (MethodHandle) argument[1];
+ * MethodType dynamicMethodType = (MethodType) argument[2];
+ * boolean serializable = (flags{@code &} 1) != 0;
+ * {@code List
+ */
+ enum UsingMethodHandleLookup implements Loader {
+
+ /**
+ * The singleton instance.
+ */
+ INSTANCE;
+
+ /**
+ * {@inheritDoc}
+ */
+ public void apply(MethodVisitor methodVisitor) {
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 4);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "revealDirect", "(Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/MethodHandleInfo;", false);
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 10);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 10);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/lang/invoke/MethodHandleInfo", "getModifiers", "()I", true);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/reflect/Modifier", "isProtected", "(I)Z", false);
+ Label first = new Label();
+ methodVisitor.visitJumpInsn(Opcodes.IFEQ, first);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "lookupClass", "()Ljava/lang/Class;", false);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 10);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/lang/invoke/MethodHandleInfo", "getDeclaringClass", "()Ljava/lang/Class;", true);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "sun/invoke/util/VerifyAccess", "isSamePackage", "(Ljava/lang/Class;Ljava/lang/Class;)Z", false);
+ Label second = new Label();
+ methodVisitor.visitJumpInsn(Opcodes.IFEQ, second);
+ methodVisitor.visitLabel(first);
+ methodVisitor.visitFrame(Opcodes.F_FULL, 11, new Object[]{"java/lang/invoke/MethodHandles$Lookup", "java/lang/String", "java/lang/invoke/MethodType", "java/lang/invoke/MethodType", "java/lang/invoke/MethodHandle", "java/lang/invoke/MethodType", Opcodes.INTEGER, "java/util/List", "java/util/List", "[B", "java/lang/invoke/MethodHandleInfo"}, 0, new Object[]{});
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 10);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/lang/invoke/MethodHandleInfo", "getReferenceKind", "()I", true);
+ methodVisitor.visitIntInsn(Opcodes.BIPUSH, 7);
+ Label third = new Label();
+ methodVisitor.visitJumpInsn(Opcodes.IF_ICMPNE, third);
+ methodVisitor.visitLabel(second);
+ methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+ methodVisitor.visitInsn(Opcodes.ICONST_1);
+ Label forth = new Label();
+ methodVisitor.visitJumpInsn(Opcodes.GOTO, forth);
+ methodVisitor.visitLabel(third);
+ methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+ methodVisitor.visitInsn(Opcodes.ICONST_0);
+ methodVisitor.visitLabel(forth);
+ methodVisitor.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{Opcodes.INTEGER});
+ methodVisitor.visitVarInsn(Opcodes.ISTORE, 11);
+ methodVisitor.visitVarInsn(Opcodes.ILOAD, 11);
+ Label fifth = new Label();
+ methodVisitor.visitJumpInsn(Opcodes.IFEQ, fifth);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 9);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 10);
+ methodVisitor.visitInsn(Opcodes.ICONST_1);
+ methodVisitor.visitInsn(Opcodes.ICONST_2);
+ methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/invoke/MethodHandles$Lookup$ClassOption");
+ methodVisitor.visitInsn(Opcodes.DUP);
+ methodVisitor.visitInsn(Opcodes.ICONST_0);
+ methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/invoke/MethodHandles$Lookup$ClassOption", "NESTMATE", "Ljava/lang/invoke/MethodHandles$Lookup$ClassOption;");
+ methodVisitor.visitInsn(Opcodes.AASTORE);
+ methodVisitor.visitInsn(Opcodes.DUP);
+ methodVisitor.visitInsn(Opcodes.ICONST_1);
+ methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/invoke/MethodHandles$Lookup$ClassOption", "STRONG", "Ljava/lang/invoke/MethodHandles$Lookup$ClassOption;");
+ methodVisitor.visitInsn(Opcodes.AASTORE);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "defineHiddenClassWithClassData", "([BLjava/lang/Object;Z[Ljava/lang/invoke/MethodHandles$Lookup$ClassOption;)Ljava/lang/invoke/MethodHandles$Lookup;", false);
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 12);
+ Label sixth = new Label();
+ methodVisitor.visitLabel(sixth);
+ Label seventh = new Label();
+ methodVisitor.visitJumpInsn(Opcodes.GOTO, seventh);
+ methodVisitor.visitLabel(fifth);
+ methodVisitor.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, 0, null);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 9);
+ methodVisitor.visitInsn(Opcodes.ICONST_1);
+ methodVisitor.visitInsn(Opcodes.ICONST_2);
+ methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/invoke/MethodHandles$Lookup$ClassOption");
+ methodVisitor.visitInsn(Opcodes.DUP);
+ methodVisitor.visitInsn(Opcodes.ICONST_0);
+ methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/invoke/MethodHandles$Lookup$ClassOption", "NESTMATE", "Ljava/lang/invoke/MethodHandles$Lookup$ClassOption;");
+ methodVisitor.visitInsn(Opcodes.AASTORE);
+ methodVisitor.visitInsn(Opcodes.DUP);
+ methodVisitor.visitInsn(Opcodes.ICONST_1);
+ methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/invoke/MethodHandles$Lookup$ClassOption", "STRONG", "Ljava/lang/invoke/MethodHandles$Lookup$ClassOption;");
+ methodVisitor.visitInsn(Opcodes.AASTORE);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "defineHiddenClass", "([BZ[Ljava/lang/invoke/MethodHandles$Lookup$ClassOption;)Ljava/lang/invoke/MethodHandles$Lookup;", false);
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 12);
+ methodVisitor.visitLabel(seventh);
+ methodVisitor.visitFrame(Opcodes.F_APPEND, 1, new Object[]{"java/lang/invoke/MethodHandles$Lookup"}, 0, null);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 12);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "lookupClass", "()Ljava/lang/Class;", false);
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 10);
+ methodVisitor.visitFrame(Opcodes.F_FULL, 10, new Object[]{"java/lang/invoke/MethodHandles$Lookup",
+ "java/lang/String",
+ "java/lang/invoke/MethodType",
+ "java/lang/invoke/MethodType",
+ "java/lang/invoke/MethodHandle",
+ "java/lang/invoke/MethodType",
+ Opcodes.INTEGER,
+ "java/util/List",
+ "java/util/List",
+ "java/lang/Class"}, 0, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getStackSize() {
+ return 8;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getLocalVariableLength() {
+ return 15;
+ }
+ }
+
+ /**
+ * A loader that is using unsafe API to load a lambda implementation. The code for loading
+ * the class looks similar to the following:
+ *
+ * MethodHandleInfo info = caller.revealDirect(implementation);
+ * boolean classData = (Modifier.isProtected(info.getModifiers())
+ * {@code &&} !VerifyAccess.isSamePackage(caller.lookupClass(), info.getDeclaringClass()))
+ * || info.getReferenceKind() == Opcodes.H_INVOKESPECIAL;
+ * MethodHandles.Lookup lookup;
+ * if (classData) {
+ * lookup = caller.defineHiddenClassWithClassData(binaryRepresentation,
+ * info,
+ * true,
+ * MethodHandles.Lookup.ClassOption.NESTMATE,
+ * MethodHandles.Lookup.ClassOption.STRONG);
+ * } else {
+ * lookup = caller.defineHiddenClass(binaryRepresentation,
+ * true,
+ * MethodHandles.Lookup.ClassOption.NESTMATE,
+ * MethodHandles.Lookup.ClassOption.STRONG);
+ * }
+ * {@code Class>} lambdaClass = lookup.lookupClass();
+ *
+ */
+ enum UsingUnsafe implements Loader {
+
+ /**
+ * A loader that uses {@code jdk.internal.misc.Unsafe}.
+ */
+ JDK_INTERNAL_MISC_UNSAFE("jdk/internal/misc/Unsafe"),
+
+ /**
+ * A loader that uses {@code sun.misc.Unsafe}.
+ */
+ SUN_MISC_UNSAFE("sun/misc/Unsafe");
+
+ /**
+ * The internal name of the unsafe type.
+ */
+ private final String type;
+
+ /**
+ * Creates a new loader using unsafe API.
+ *
+ * @param type The internal name of the unsafe type.
+ */
+ UsingUnsafe(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Returns the internal name of the unsafe type.
+ *
+ * @return The internal name of the unsafe type.
+ */
+ protected String getType() {
+ return type;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void apply(MethodVisitor methodVisitor) {
+ methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, type, "getUnsafe", "()L" + type + ";", false);
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 11);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 11);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "lookupClass", "()Ljava/lang/Class;", false);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 9);
+ methodVisitor.visitInsn(Opcodes.ACONST_NULL);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, type, "defineAnonymousClass", "(Ljava/lang/Class;[B[Ljava/lang/Object;)Ljava/lang/Class;", false);
+ methodVisitor.visitVarInsn(Opcodes.ASTORE, 10);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 11);
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 10);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, type, "ensureClassInitialized", "(Ljava/lang/Class;)V", false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getStackSize() {
+ return 4;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getLocalVariableLength() {
+ return 13;
+ }
+ }
+ }
+ }
+
+ /**
+ * A factory that creates instances that represent lambda expressions.
+ */
+ @HashCodeAndEqualsPlugin.Enhance
+ protected static class LambdaInstanceFactory {
+
+ /**
+ * The name of a factory for a lambda expression.
+ */
+ private static final String LAMBDA_FACTORY = "get$Lambda";
+
+ /**
+ * A prefix for a field that represents a property of a lambda expression.
+ */
+ private static final String FIELD_PREFIX = "arg$";
+
+ /**
+ * The infix to use for naming classes that represent lambda expression. The additional prefix
+ * is necessary because the subsequent counter is not sufficient to keep names unique compared
+ * to the original factory.
+ */
+ private static final String LAMBDA_TYPE_INFIX = "$$Lambda$ByteBuddy$";
+
+ /**
+ * A type-safe constant to express that a class is not already loaded when applying a class file transformer.
+ */
+ @AlwaysNull
+ private static final Class> NOT_PREVIOUSLY_DEFINED = null;
+
+ /**
+ * A counter for naming lambda expressions randomly.
+ */
+ private static final AtomicInteger LAMBDA_NAME_COUNTER = new AtomicInteger();
+
+ /**
+ * The Byte Buddy instance to use for creating lambda objects.
+ */
+ private final ByteBuddy byteBuddy;
+
+ /**
+ * Creates a new lambda instance factory.
+ *
+ * @param byteBuddy The Byte Buddy instance to use for creating lambda objects.
+ */
+ protected LambdaInstanceFactory(ByteBuddy byteBuddy) {
+ this.byteBuddy = byteBuddy;
+ }
+
+ /**
+ * Applies this lambda meta factory.
+ *
+ * @param targetTypeLookup A lookup context representing the creating class of this lambda expression.
+ * @param lambdaMethodName The name of the lambda expression's represented method.
+ * @param factoryMethodType The type of the lambda expression's represented method.
+ * @param lambdaMethodType The type of the lambda expression's factory method.
+ * @param targetMethodHandle A handle representing the target of the lambda expression's method.
+ * @param specializedLambdaMethodType A specialization of the type of the lambda expression's represented method.
+ * @param serializable {@code true} if the lambda expression should be serializable.
+ * @param markerInterfaces A list of interfaces for the lambda expression to represent.
+ * @param additionalBridges A list of additional bridge methods to be implemented by the lambda expression.
+ * @param classFileTransformers A collection of class file transformers to apply when creating the class.
+ * @return A binary representation of the transformed class file.
+ */
+ public byte[] make(Object targetTypeLookup,
+ String lambdaMethodName,
+ Object factoryMethodType,
+ Object lambdaMethodType,
+ Object targetMethodHandle,
+ Object specializedLambdaMethodType,
+ boolean serializable,
+ List
+ * Unsafe unsafe = Unsafe.getUnsafe();
+ * {@code Class>} lambdaClass = unsafe.defineAnonymousClass(caller.lookupClass(),
+ * binaryRepresentation,
+ * null);
+ * unsafe.ensureClassInitialized(lambdaClass);
+ *
+ * Allows for a short period where neither class file transformer is registered. This might allow
+ * for classes to execute without instrumentation if they are loaded in a short moment where neither
+ * transformer is registered. In some rare cases, this might also cause that these classes are not
+ * instrumented as a result of the patching.
+ */
+ GAP {
+ @Override
+ protected Handler toHandler(ResettableClassFileTransformer classFileTransformer) {
+ return new Handler.ForPatchWithGap(classFileTransformer);
+ }
+ },
+
+ /**
+ * Allows for a short period where both class file transformer are registered. This might allow
+ * for classes to apply both instrumentations. In some rare cases, this might also cause that both
+ * instrumentations are permanently applied.
+ */
+ OVERLAP {
+ @Override
+ protected Handler toHandler(ResettableClassFileTransformer classFileTransformer) {
+ return new Handler.ForPatchWithOverlap(classFileTransformer);
+ }
+ };
+
+ /**
+ * Resolves this strategy to a handler.
+ *
+ * @param classFileTransformer The class file transformer to deregister.
+ * @return The handler to apply.
+ */
+ protected abstract Handler toHandler(ResettableClassFileTransformer classFileTransformer);
+
+ /**
+ * A handler to allow for callbacks prior and after registering a {@link ClassFileTransformer}.
*/
- protected enum MetaFactoryRedirection implements AsmVisitorWrapper.ForDeclaredMethods.MethodVisitorWrapper {
+ protected interface Handler {
/**
- * The singleton instance.
+ * Invoked prior to registering a class file transformer.
+ *
+ * @param instrumentation The instrumentation to use.
*/
- INSTANCE;
+ void onBeforeRegistration(Instrumentation instrumentation);
/**
- * {@inheritDoc}
+ * Invoked right after registering a class file transformer.
+ *
+ * @param instrumentation The instrumentation to use.
*/
- public MethodVisitor wrap(TypeDescription instrumentedType,
- MethodDescription instrumentedMethod,
- MethodVisitor methodVisitor,
- Implementation.Context implementationContext,
- TypePool typePool,
- int writerFlags,
- int readerFlags) {
- methodVisitor.visitCode();
- methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, UNSAFE_CLASS, "getUnsafe", "()L" + UNSAFE_CLASS + ";", false);
- methodVisitor.visitVarInsn(Opcodes.ASTORE, 6);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 6);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "lookupClass", "()Ljava/lang/Class;", false);
- methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/ClassLoader", "getSystemClassLoader", "()Ljava/lang/ClassLoader;", false);
- methodVisitor.visitLdcInsn("net.bytebuddy.agent.builder.LambdaFactory");
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/ClassLoader", "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;", false);
- methodVisitor.visitLdcInsn("make");
- methodVisitor.visitIntInsn(Opcodes.BIPUSH, 9);
- methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_0);
- methodVisitor.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_1);
- methodVisitor.visitLdcInsn(Type.getType("Ljava/lang/String;"));
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_2);
- methodVisitor.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_3);
- methodVisitor.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_4);
- methodVisitor.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_5);
- methodVisitor.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitIntInsn(Opcodes.BIPUSH, 6);
- methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;");
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitIntInsn(Opcodes.BIPUSH, 7);
- methodVisitor.visitLdcInsn(Type.getType("Ljava/util/List;"));
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitIntInsn(Opcodes.BIPUSH, 8);
- methodVisitor.visitLdcInsn(Type.getType("Ljava/util/List;"));
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
- methodVisitor.visitInsn(Opcodes.ACONST_NULL);
- methodVisitor.visitIntInsn(Opcodes.BIPUSH, 9);
- methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_0);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_1);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_2);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 2);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_3);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_4);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 4);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_5);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 5);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitIntInsn(Opcodes.BIPUSH, 6);
- methodVisitor.visitInsn(Opcodes.ICONST_0);
- methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitIntInsn(Opcodes.BIPUSH, 7);
- methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Collections", "emptyList", "()Ljava/util/List;", false);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitIntInsn(Opcodes.BIPUSH, 8);
- methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Collections", "emptyList", "()Ljava/util/List;", false);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
- methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, "[B");
- methodVisitor.visitInsn(Opcodes.ACONST_NULL);
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, UNSAFE_CLASS, "defineAnonymousClass", "(Ljava/lang/Class;[B[Ljava/lang/Object;)Ljava/lang/Class;", false);
- methodVisitor.visitVarInsn(Opcodes.ASTORE, 7);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 6);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 7);
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, UNSAFE_CLASS, "ensureClassInitialized", "(Ljava/lang/Class;)V", false);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 2);
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/invoke/MethodType", "parameterCount", "()I", false);
- Label conditionalDefault = new Label();
- methodVisitor.visitJumpInsn(Opcodes.IFNE, conditionalDefault);
- methodVisitor.visitTypeInsn(Opcodes.NEW, "java/lang/invoke/ConstantCallSite");
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 2);
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/invoke/MethodType", "returnType", "()Ljava/lang/Class;", false);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 7);
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getDeclaredConstructors", "()[Ljava/lang/reflect/Constructor;", false);
- methodVisitor.visitInsn(Opcodes.ICONST_0);
- methodVisitor.visitInsn(Opcodes.AALOAD);
- methodVisitor.visitInsn(Opcodes.ICONST_0);
- methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Constructor", "newInstance", "([Ljava/lang/Object;)Ljava/lang/Object;", false);
- methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/invoke/MethodHandles", "constant", "(Ljava/lang/Class;Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;", false);
- methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/invoke/ConstantCallSite", "
- * public static CallSite metafactory(MethodHandles.Lookup caller,
- * String invokedName,
- * MethodType invokedType,
- * MethodType samMethodType,
- * MethodHandle implMethod,
- * MethodType instantiatedMethodType) throws Exception {
- * Unsafe unsafe = Unsafe.getUnsafe();
- * {@code Class>} lambdaClass = unsafe.defineAnonymousClass(caller.lookupClass(),
- * (byte[]) ClassLoader.getSystemClassLoader().loadClass("net.bytebuddy.agent.builder.LambdaFactory").getDeclaredMethod("make",
- * Object.class,
- * String.class,
- * Object.class,
- * Object.class,
- * Object.class,
- * Object.class,
- * boolean.class,
- * List.class,
- * List.class).invoke(null,
- * caller,
- * invokedName,
- * invokedType,
- * samMethodType,
- * implMethod,
- * instantiatedMethodType,
- * false,
- * Collections.emptyList(),
- * Collections.emptyList()),
- * null);
- * unsafe.ensureClassInitialized(lambdaClass);
- * return invokedType.parameterCount() == 0
- * ? new ConstantCallSite(MethodHandles.constant(invokedType.returnType(), lambdaClass.getDeclaredConstructors()[0].newInstance()))
- * : new ConstantCallSite(MethodHandles.Lookup.IMPL_LOOKUP.findStatic(lambdaClass, "get$Lambda", invokedType));
- *
- */
- protected enum AlternativeMetaFactoryRedirection implements AsmVisitorWrapper.ForDeclaredMethods.MethodVisitorWrapper {
+ /**
+ * A non-operational handler.
+ */
+ enum NoOp implements Handler {
+
+ /**
+ * The singleton instance.
+ */
+ INSTANCE;
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onBeforeRegistration(Instrumentation instrumentation) {
+ /* do nothing */
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onAfterRegistration(Instrumentation instrumentation) {
+ /* do nothing */
+ }
+ }
/**
- * The singleton instance.
+ * A handler for patching by {@link PatchMode#GAP}.
*/
- INSTANCE;
+ @HashCodeAndEqualsPlugin.Enhance
+ class ForPatchWithGap implements Handler {
+
+ /**
+ * The class file transformer to deregister.
+ */
+ private final ResettableClassFileTransformer classFileTransformer;
+
+ /**
+ * Creates a new handler.
+ *
+ * @param classFileTransformer The class file transformer to deregister.
+ */
+ protected ForPatchWithGap(ResettableClassFileTransformer classFileTransformer) {
+ this.classFileTransformer = classFileTransformer;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onBeforeRegistration(Instrumentation instrumentation) {
+ if (!classFileTransformer.reset(instrumentation, RedefinitionStrategy.DISABLED)) {
+ throw new IllegalArgumentException("Failed to deregister patched class file transformer: " + classFileTransformer);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onAfterRegistration(Instrumentation instrumentation) {
+ /* do nothing */
+ }
+ }
/**
- * {@inheritDoc}
+ * A handler for patching by {@link PatchMode#OVERLAP}.
*/
- public MethodVisitor wrap(TypeDescription instrumentedType,
- MethodDescription instrumentedMethod,
- MethodVisitor methodVisitor,
- Implementation.Context implementationContext,
- TypePool typePool,
- int writerFlags,
- int readerFlags) {
- methodVisitor.visitCode();
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
- methodVisitor.visitInsn(Opcodes.ICONST_3);
- methodVisitor.visitInsn(Opcodes.AALOAD);
- methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Integer");
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
- methodVisitor.visitVarInsn(Opcodes.ISTORE, 4);
- methodVisitor.visitInsn(Opcodes.ICONST_4);
- methodVisitor.visitVarInsn(Opcodes.ISTORE, 5);
- methodVisitor.visitVarInsn(Opcodes.ILOAD, 4);
- methodVisitor.visitInsn(Opcodes.ICONST_2);
- methodVisitor.visitInsn(Opcodes.IAND);
- Label markerInterfaceLoop = new Label();
- methodVisitor.visitJumpInsn(Opcodes.IFEQ, markerInterfaceLoop);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
- methodVisitor.visitVarInsn(Opcodes.ILOAD, 5);
- methodVisitor.visitIincInsn(5, 1);
- methodVisitor.visitInsn(Opcodes.AALOAD);
- methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Integer");
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
- methodVisitor.visitVarInsn(Opcodes.ISTORE, 7);
- methodVisitor.visitVarInsn(Opcodes.ILOAD, 7);
- methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
- methodVisitor.visitVarInsn(Opcodes.ASTORE, 6);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
- methodVisitor.visitVarInsn(Opcodes.ILOAD, 5);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 6);
- methodVisitor.visitInsn(Opcodes.ICONST_0);
- methodVisitor.visitVarInsn(Opcodes.ILOAD, 7);
- methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V", false);
- methodVisitor.visitVarInsn(Opcodes.ILOAD, 5);
- methodVisitor.visitVarInsn(Opcodes.ILOAD, 7);
- methodVisitor.visitInsn(Opcodes.IADD);
- methodVisitor.visitVarInsn(Opcodes.ISTORE, 5);
- Label markerInterfaceExit = new Label();
- methodVisitor.visitJumpInsn(Opcodes.GOTO, markerInterfaceExit);
- methodVisitor.visitLabel(markerInterfaceLoop);
- methodVisitor.visitFrame(Opcodes.F_APPEND, 2, new Object[]{Opcodes.INTEGER, Opcodes.INTEGER}, 0, null);
- methodVisitor.visitInsn(Opcodes.ICONST_0);
- methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
- methodVisitor.visitVarInsn(Opcodes.ASTORE, 6);
- methodVisitor.visitLabel(markerInterfaceExit);
- methodVisitor.visitFrame(Opcodes.F_APPEND, 1, new Object[]{"[Ljava/lang/Class;"}, 0, null);
- methodVisitor.visitVarInsn(Opcodes.ILOAD, 4);
- methodVisitor.visitInsn(Opcodes.ICONST_4);
- methodVisitor.visitInsn(Opcodes.IAND);
- Label additionalBridgesLoop = new Label();
- methodVisitor.visitJumpInsn(Opcodes.IFEQ, additionalBridgesLoop);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
- methodVisitor.visitVarInsn(Opcodes.ILOAD, 5);
- methodVisitor.visitIincInsn(5, 1);
- methodVisitor.visitInsn(Opcodes.AALOAD);
- methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Integer");
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
- methodVisitor.visitVarInsn(Opcodes.ISTORE, 8);
- methodVisitor.visitVarInsn(Opcodes.ILOAD, 8);
- methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/invoke/MethodType");
- methodVisitor.visitVarInsn(Opcodes.ASTORE, 7);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
- methodVisitor.visitVarInsn(Opcodes.ILOAD, 5);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 7);
- methodVisitor.visitInsn(Opcodes.ICONST_0);
- methodVisitor.visitVarInsn(Opcodes.ILOAD, 8);
- methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V", false);
- Label additionalBridgesExit = new Label();
- methodVisitor.visitJumpInsn(Opcodes.GOTO, additionalBridgesExit);
- methodVisitor.visitLabel(additionalBridgesLoop);
- methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
- methodVisitor.visitInsn(Opcodes.ICONST_0);
- methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/invoke/MethodType");
- methodVisitor.visitVarInsn(Opcodes.ASTORE, 7);
- methodVisitor.visitLabel(additionalBridgesExit);
- methodVisitor.visitFrame(Opcodes.F_APPEND, 1, new Object[]{"[Ljava/lang/invoke/MethodType;"}, 0, null);
- methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, UNSAFE_CLASS, "getUnsafe", "()L" + UNSAFE_CLASS + ";", false);
- methodVisitor.visitVarInsn(Opcodes.ASTORE, 8);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 8);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "lookupClass", "()Ljava/lang/Class;", false);
- methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/ClassLoader", "getSystemClassLoader", "()Ljava/lang/ClassLoader;", false);
- methodVisitor.visitLdcInsn("net.bytebuddy.agent.builder.LambdaFactory");
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/ClassLoader", "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;", false);
- methodVisitor.visitLdcInsn("make");
- methodVisitor.visitIntInsn(Opcodes.BIPUSH, 9);
- methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_0);
- methodVisitor.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_1);
- methodVisitor.visitLdcInsn(Type.getType("Ljava/lang/String;"));
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_2);
- methodVisitor.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_3);
- methodVisitor.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_4);
- methodVisitor.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_5);
- methodVisitor.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitIntInsn(Opcodes.BIPUSH, 6);
- methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;");
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitIntInsn(Opcodes.BIPUSH, 7);
- methodVisitor.visitLdcInsn(Type.getType("Ljava/util/List;"));
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitIntInsn(Opcodes.BIPUSH, 8);
- methodVisitor.visitLdcInsn(Type.getType("Ljava/util/List;"));
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
- methodVisitor.visitInsn(Opcodes.ACONST_NULL);
- methodVisitor.visitIntInsn(Opcodes.BIPUSH, 9);
- methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_0);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_1);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_2);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 2);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_3);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
- methodVisitor.visitInsn(Opcodes.ICONST_0);
- methodVisitor.visitInsn(Opcodes.AALOAD);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_4);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
- methodVisitor.visitInsn(Opcodes.ICONST_1);
- methodVisitor.visitInsn(Opcodes.AALOAD);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitInsn(Opcodes.ICONST_5);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 3);
- methodVisitor.visitInsn(Opcodes.ICONST_2);
- methodVisitor.visitInsn(Opcodes.AALOAD);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitIntInsn(Opcodes.BIPUSH, 6);
- methodVisitor.visitVarInsn(Opcodes.ILOAD, 4);
- methodVisitor.visitInsn(Opcodes.ICONST_1);
- methodVisitor.visitInsn(Opcodes.IAND);
- Label callSiteConditional = new Label();
- methodVisitor.visitJumpInsn(Opcodes.IFEQ, callSiteConditional);
- methodVisitor.visitInsn(Opcodes.ICONST_1);
- Label callSiteAlternative = new Label();
- methodVisitor.visitJumpInsn(Opcodes.GOTO, callSiteAlternative);
- methodVisitor.visitLabel(callSiteConditional);
- methodVisitor.visitFrame(Opcodes.F_FULL, 9, new Object[]{"java/lang/invoke/MethodHandles$Lookup", "java/lang/String", "java/lang/invoke/MethodType", "[Ljava/lang/Object;", Opcodes.INTEGER, Opcodes.INTEGER, "[Ljava/lang/Class;", "[Ljava/lang/invoke/MethodType;", UNSAFE_CLASS}, 7, new Object[]{UNSAFE_CLASS, "java/lang/Class", "java/lang/reflect/Method", Opcodes.NULL, "[Ljava/lang/Object;", "[Ljava/lang/Object;", Opcodes.INTEGER});
- methodVisitor.visitInsn(Opcodes.ICONST_0);
- methodVisitor.visitLabel(callSiteAlternative);
- methodVisitor.visitFrame(Opcodes.F_FULL, 9, new Object[]{"java/lang/invoke/MethodHandles$Lookup", "java/lang/String", "java/lang/invoke/MethodType", "[Ljava/lang/Object;", Opcodes.INTEGER, Opcodes.INTEGER, "[Ljava/lang/Class;", "[Ljava/lang/invoke/MethodType;", UNSAFE_CLASS}, 8, new Object[]{UNSAFE_CLASS, "java/lang/Class", "java/lang/reflect/Method", Opcodes.NULL, "[Ljava/lang/Object;", "[Ljava/lang/Object;", Opcodes.INTEGER, Opcodes.INTEGER});
- methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitIntInsn(Opcodes.BIPUSH, 7);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 6);
- methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Arrays", "asList", "([Ljava/lang/Object;)Ljava/util/List;", false);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitIntInsn(Opcodes.BIPUSH, 8);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 7);
- methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Arrays", "asList", "([Ljava/lang/Object;)Ljava/util/List;", false);
- methodVisitor.visitInsn(Opcodes.AASTORE);
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
- methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, "[B");
- methodVisitor.visitInsn(Opcodes.ACONST_NULL);
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, UNSAFE_CLASS, "defineAnonymousClass", "(Ljava/lang/Class;[B[Ljava/lang/Object;)Ljava/lang/Class;", false);
- methodVisitor.visitVarInsn(Opcodes.ASTORE, 9);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 8);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 9);
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, UNSAFE_CLASS, "ensureClassInitialized", "(Ljava/lang/Class;)V", false);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 2);
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/invoke/MethodType", "parameterCount", "()I", false);
- Label callSiteJump = new Label();
- methodVisitor.visitJumpInsn(Opcodes.IFNE, callSiteJump);
- methodVisitor.visitTypeInsn(Opcodes.NEW, "java/lang/invoke/ConstantCallSite");
- methodVisitor.visitInsn(Opcodes.DUP);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 2);
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/invoke/MethodType", "returnType", "()Ljava/lang/Class;", false);
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 9);
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getDeclaredConstructors", "()[Ljava/lang/reflect/Constructor;", false);
- methodVisitor.visitInsn(Opcodes.ICONST_0);
- methodVisitor.visitInsn(Opcodes.AALOAD);
- methodVisitor.visitInsn(Opcodes.ICONST_0);
- methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
- methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Constructor", "newInstance", "([Ljava/lang/Object;)Ljava/lang/Object;", false);
- methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/invoke/MethodHandles", "constant", "(Ljava/lang/Class;Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;", false);
- methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/invoke/ConstantCallSite", "
- * public static CallSite altMetafactory(MethodHandles.Lookup caller,
- * String invokedName,
- * MethodType invokedType,
- * Object... args) throws Exception {
- * int flags = (Integer) args[3];
- * int argIndex = 4;
- * {@code Class>[]} markerInterface;
- * if ((flags {@code &} FLAG_MARKERS) != 0) {
- * int markerCount = (Integer) args[argIndex++];
- * markerInterface = new {@code Class>}[markerCount];
- * System.arraycopy(args, argIndex, markerInterface, 0, markerCount);
- * argIndex += markerCount;
- * } else {
- * markerInterface = new {@code Class>}[0];
- * }
- * MethodType[] additionalBridge;
- * if ((flags {@code &} FLAG_BRIDGES) != 0) {
- * int bridgeCount = (Integer) args[argIndex++];
- * additionalBridge = new MethodType[bridgeCount];
- * System.arraycopy(args, argIndex, additionalBridge, 0, bridgeCount);
- * // argIndex += bridgeCount;
- * } else {
- * additionalBridge = new MethodType[0];
- * }
- * Unsafe unsafe = Unsafe.getUnsafe();
- * {@code Class>} lambdaClass = unsafe.defineAnonymousClass(caller.lookupClass(),
- * (byte[]) ClassLoader.getSystemClassLoader().loadClass("net.bytebuddy.agent.builder.LambdaFactory").getDeclaredMethod("make",
- * Object.class,
- * String.class,
- * Object.class,
- * Object.class,
- * Object.class,
- * Object.class,
- * boolean.class,
- * List.class,
- * List.class).invoke(null,
- * caller,
- * invokedName,
- * invokedType,
- * args[0],
- * args[1],
- * args[2],
- * (flags {@code &} FLAG_SERIALIZABLE) != 0,
- * Arrays.asList(markerInterface),
- * Arrays.asList(additionalBridge)),
- * null);
- * unsafe.ensureClassInitialized(lambdaClass);
- * return invokedType.parameterCount() == 0
- * ? new ConstantCallSite(MethodHandles.constant(invokedType.returnType(), lambdaClass.getDeclaredConstructors()[0].newInstance()))
- * : new ConstantCallSite(MethodHandles.Lookup.IMPL_LOOKUP.findStatic(lambdaClass, "get$Lambda", invokedType));
- * }
- *
The type that is produced by chaining a matcher.
@@ -11699,6 +12915,7 @@
typeStrategy,
locationStrategy,
nativeMethodStrategy,
+ warmupStrategy,
transformerDecorator,
initializationStrategy,
redefinitionStrategy,
@@ -11776,6 +12993,7 @@
typeStrategy,
locationStrategy,
nativeMethodStrategy,
+ warmupStrategy,
transformerDecorator,
initializationStrategy,
redefinitionStrategy,
@@ -11837,6 +13055,7 @@
* @param typeStrategy The definition handler to use.
* @param locationStrategy The location strategy to use.
* @param nativeMethodStrategy The native method strategy to apply.
+ * @param warmupStrategy The warmup strategy to use.
* @param transformerDecorator A decorator to wrap the created class file transformer.
* @param initializationStrategy The initialization strategy to use for transformed types.
* @param redefinitionStrategy The redefinition strategy to apply.
@@ -11861,6 +13080,7 @@
TypeStrategy typeStrategy,
LocationStrategy locationStrategy,
NativeMethodStrategy nativeMethodStrategy,
+ WarmupStrategy warmupStrategy,
TransformerDecorator transformerDecorator,
InitializationStrategy initializationStrategy,
RedefinitionStrategy redefinitionStrategy,
@@ -11883,6 +13103,7 @@
typeStrategy,
locationStrategy,
nativeMethodStrategy,
+ warmupStrategy,
transformerDecorator,
initializationStrategy,
redefinitionStrategy,
@@ -11914,6 +13135,7 @@
typeStrategy,
locationStrategy,
nativeMethodStrategy,
+ warmupStrategy,
transformerDecorator,
initializationStrategy,
redefinitionStrategy,
@@ -11952,6 +13174,7 @@
typeStrategy,
locationStrategy,
nativeMethodStrategy,
+ warmupStrategy,
transformerDecorator,
initializationStrategy,
redefinitionStrategy,
@@ -11983,6 +13206,7 @@
typeStrategy,
locationStrategy,
nativeMethodStrategy,
+ warmupStrategy,
transformerDecorator,
initializationStrategy,
redefinitionStrategy,
@@ -12056,6 +13280,7 @@
typeStrategy,
locationStrategy,
nativeMethodStrategy,
+ warmupStrategy,
transformerDecorator,
initializationStrategy,
redefinitionStrategy,
diff -Nru byte-buddy-1.11.4/byte-buddy-dep/src/main/java/net/bytebuddy/agent/builder/LambdaFactory.java byte-buddy-1.12.21/byte-buddy-dep/src/main/java/net/bytebuddy/agent/builder/LambdaFactory.java
--- byte-buddy-1.11.4/byte-buddy-dep/src/main/java/net/bytebuddy/agent/builder/LambdaFactory.java 2021-06-19 21:31:07.000000000 +0000
+++ byte-buddy-1.12.21/byte-buddy-dep/src/main/java/net/bytebuddy/agent/builder/LambdaFactory.java 2023-01-04 22:45:00.000000000 +0000
@@ -47,7 +47,7 @@
* A mapping of all registered class file transformers and their lambda factories, linked in their application order.
* This field must not be accessed directly but only by reading this class from the system class loader.
*/
- @SuppressFBWarnings(value = "MS_MUTABLE_COLLECTION_PKGPROTECT", justification = "The field must be accessible by different class loader instances")
+ @SuppressFBWarnings(value = "MS_MUTABLE_COLLECTION_PKGPROTECT", justification = "The field must be accessible by different class loader instances.")
public static final Map The annotation type.
* @return A factory for creating an offset mapping that binds the supplied value.
*/
- public static OffsetMapping.Factory of(Class annotationType, Object value) {
+ public static OffsetMapping.Factory of(Class annotationType, @MaybeNull Object value) {
StackManipulation stackManipulation;
TypeDescription typeDescription;
if (value == null) {
@@ -3647,13 +3976,13 @@
typeDescription = TypeDescription.ForLoadedType.of(double.class);
} else if (value instanceof String) {
stackManipulation = new TextConstant((String) value);
- typeDescription = TypeDescription.STRING;
+ typeDescription = TypeDescription.ForLoadedType.of(String.class);
} else if (value instanceof Class>) {
stackManipulation = ClassConstant.of(TypeDescription.ForLoadedType.of((Class>) value));
- typeDescription = TypeDescription.CLASS;
+ typeDescription = TypeDescription.ForLoadedType.of(Class.class);
} else if (value instanceof TypeDescription) {
stackManipulation = ClassConstant.of((TypeDescription) value);
- typeDescription = TypeDescription.CLASS;
+ typeDescription = TypeDescription.ForLoadedType.of(Class.class);
} else if (value instanceof Enum>) {
stackManipulation = FieldAccess.forEnumeration(new EnumerationDescription.ForLoadedEnumeration((Enum>) value));
typeDescription = TypeDescription.ForLoadedType.of(((Enum>) value).getDeclaringClass());
@@ -3865,7 +4194,7 @@
}
return new ForStackManipulation(MethodInvocation.invoke(bootstrapMethod).dynamic(methodCandidates.getOnly().getInternalName(),
target.getType().asErasure(),
- methodCandidates.getOnly().getParameters().asTypeList().asErasures(),
+ Collections.