private static ConstantCallSite internalBootstrap()

in apm-agent-core/src/main/java/co/elastic/apm/agent/bci/IndyBootstrap.java [428:513]


    private static ConstantCallSite internalBootstrap(MethodHandles.Lookup lookup, String adviceMethodName, MethodType adviceMethodType, Object[] args) {
        try {
            if (callDepth.isNestedCallAndIncrement()) {
                // avoid re-entrancy and stack overflow errors
                // may happen when bootstrapping an instrumentation that also gets triggered during the bootstrap
                // for example, adding correlation ids to the thread context when executing logger.debug.
                if (!loggingForNestedCall.isNestedCallAndIncrement()) {
                    // We might be unlucky and cause an infinite recurison through logger()
                    // for this reason we have the loggingForNestedCall in place to prevent this recursion
                    logger().warn("Nested instrumented invokedynamic instruction linkage detected", new Throwable());
                }
                loggingForNestedCall.decrement();
                return null;
            }
            String adviceClassName = (String) args[0];
            int enter = (Integer) args[1];
            Class<?> instrumentedType = (Class<?>) args[2];
            String instrumentedMethodName = (String) args[3];
            MethodHandle instrumentedMethod = args.length >= 5 ? (MethodHandle) args[4] : null;

            ClassLoader instrumentationClassLoader = ElasticApmAgent.getInstrumentationClassLoader(adviceClassName);
            ClassLoader targetClassLoader = lookup.lookupClass().getClassLoader();
            ClassFileLocator classFileLocator;
            List<String> pluginClasses = new ArrayList<>();
            Map<String, List<String>> requiredModuleOpens = Collections.emptyMap();
            boolean allowOtelLookupFromParent;
            if (instrumentationClassLoader instanceof ExternalPluginClassLoader) {
                allowOtelLookupFromParent = true;
                List<String> externalPluginClasses = ((ExternalPluginClassLoader) instrumentationClassLoader).getClassNames();
                for (String externalPluginClass : externalPluginClasses) {
                    if (// API classes have no dependencies and don't need to be loaded by an IndyPluginCL
                        !(externalPluginClass.startsWith("co.elastic.apm.api")) &&
                        !(externalPluginClass.startsWith("co.elastic.apm.opentracing"))
                    ) {
                        pluginClasses.add(externalPluginClass);
                    }
                }
                File agentJarFile = ElasticApmAgent.getAgentJarFile();
                if (agentJarFile == null) {
                    throw new IllegalStateException("External plugin cannot be applied - can't find agent jar");
                }
                classFileLocator = new ClassFileLocator.Compound(
                    ClassFileLocator.ForClassLoader.of(instrumentationClassLoader),
                    ClassFileLocator.ForJarFile.of(agentJarFile)
                );
            } else {
                allowOtelLookupFromParent = false;
                String pluginPackage = PluginClassLoaderRootPackageCustomizer.getPluginPackageFromClassName(adviceClassName);
                pluginClasses.addAll(getClassNamesFromBundledPlugin(pluginPackage, instrumentationClassLoader));
                requiredModuleOpens = ElasticApmAgent.getRequiredPluginModuleOpens(pluginPackage);
                classFileLocator = ClassFileLocator.ForClassLoader.of(instrumentationClassLoader);
            }
            pluginClasses.add(LOOKUP_EXPOSER_CLASS_NAME);
            ClassLoader pluginClassLoader = IndyPluginClassLoaderFactory.getOrCreatePluginClassLoader(
                targetClassLoader,
                pluginClasses,
                // we provide the instrumentation class loader as the agent class loader, but it could actually be an
                // ExternalPluginClassLoader, of which parent is the agent class loader, so this works as well.
                instrumentationClassLoader,
                classFileLocator,
                isAnnotatedWith(named(GlobalState.class.getName()))
                    // if config classes would be loaded from the plugin CL,
                    // tracer.getConfig(Config.class) would return null when called from an advice as the classes are not the same
                    .or(nameContains("Config").and(hasSuperType(is(ConfigurationOptionProvider.class)))),
                allowOtelLookupFromParent);
            if (ElasticApmAgent.areModulesSupported() && !requiredModuleOpens.isEmpty()) {
                boolean success = addRequiredModuleOpens(requiredModuleOpens, targetClassLoader, pluginClassLoader);
                if (!success) {
                    logger().error("Cannot bootstrap advice because required modules could not be opened!");
                    return null;
                }
            }
            Class<?> adviceInPluginCL = pluginClassLoader.loadClass(adviceClassName);
            Class<LookupExposer> lookupExposer = (Class<LookupExposer>) pluginClassLoader.loadClass(LOOKUP_EXPOSER_CLASS_NAME);
            // can't use MethodHandle.lookup(), see also https://github.com/elastic/apm-agent-java/issues/1450
            MethodHandles.Lookup indyLookup = (MethodHandles.Lookup) lookupExposer.getMethod("getLookup").invoke(null);
            // When calling findStatic now, the lookup class will be one that is loaded by the plugin class loader
            MethodHandle methodHandle = indyLookup.findStatic(adviceInPluginCL, adviceMethodName, adviceMethodType);
            return new ConstantCallSite(methodHandle);
        } catch (Throwable e) {
            logger().error(e.getMessage(), e);
            return null;
        } finally {
            callDepth.decrement();
        }
    }