Skip to content

Commit

Permalink
ArC: introduce optimized contexts
Browse files Browse the repository at this point in the history
  • Loading branch information
mkouba committed Oct 20, 2023
1 parent 7dcbe67 commit d39f8d5
Show file tree
Hide file tree
Showing 21 changed files with 606 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,12 @@ public class ArcConfig {
@ConfigItem
public ArcContextPropagationConfig contextPropagation;

/**
* A hint that the container should try to optimize the contexts for some of the scopes.
*/
@ConfigItem(defaultValue = "true")
public boolean optimizeContexts;

public final boolean isRemoveUnusedBeansFieldValid() {
return ALLOWED_REMOVE_UNUSED_BEANS_VALUES.contains(removeUnusedBeans.toLowerCase());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ public Integer compute(AnnotationTarget target, Collection<StereotypeInfo> stere
}

builder.setBuildCompatibleExtensions(buildCompatibleExtensions.entrypoint);
builder.setOptimizeContexts(arcConfig.optimizeContexts);

BeanProcessor beanProcessor = builder.build();
ContextRegistrar.RegistrationContext context = beanProcessor.registerCustomContexts();
Expand Down Expand Up @@ -516,6 +517,12 @@ public void generateResources(ArcConfig config,
ExecutorService executor = parallelResourceGeneration ? buildExecutor : null;
List<ResourceOutput.Resource> resources;
resources = beanProcessor.generateResources(new ReflectionRegistration() {

@Override
public void registerMethod(String declaringClass, String name, String... params) {
reflectiveMethods.produce(new ReflectiveMethodBuildItem(declaringClass, name, params));
}

@Override
public void registerMethod(MethodInfo methodInfo) {
reflectiveMethods.produce(new ReflectiveMethodBuildItem(methodInfo));
Expand Down Expand Up @@ -591,7 +598,7 @@ public ArcContainerBuildItem initializeContainer(ArcConfig config, ArcRecorder r
throws Exception {
ArcContainer container = recorder.initContainer(shutdown,
currentContextFactory.isPresent() ? currentContextFactory.get().getFactory() : null,
config.strictCompatibility);
config.strictCompatibility, config.optimizeContexts);
return new ArcContainerBuildItem(container);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@ public class ArcRecorder {
public static volatile Map<String, Function<SyntheticCreationalContext<?>, ?>> syntheticBeanProviders;

public ArcContainer initContainer(ShutdownContext shutdown, RuntimeValue<CurrentContextFactory> currentContextFactory,
boolean strictCompatibility)
boolean strictCompatibility, boolean optimizeContexts)
throws Exception {
ArcContainer container = Arc.initialize(ArcInitConfig.builder()
.setCurrentContextFactory(currentContextFactory != null ? currentContextFactory.getValue() : null)
.setStrictCompatibility(strictCompatibility).build());
ArcInitConfig.Builder builder = ArcInitConfig.builder();
builder.setCurrentContextFactory(currentContextFactory != null ? currentContextFactory.getValue() : null);
builder.setStrictCompatibility(strictCompatibility);
builder.setOptimizeContexts(optimizeContexts);
ArcContainer container = Arc.initialize(builder.build());
shutdown.addShutdownTask(new Runnable() {
@Override
public void run() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public class BeanDeployment {

private static final Logger LOGGER = Logger.getLogger(BeanDeployment.class);

private final String name;
final String name;
private final BuildContextImpl buildContext;

private final IndexView beanArchiveComputingIndex;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public static Builder builder() {
private final boolean generateSources;
private final boolean allowMocking;
private final boolean transformUnproxyableClasses;
private final boolean optimizeContexts;
private final List<Function<BeanInfo, Consumer<BytecodeCreator>>> suppressConditionGenerators;

// This predicate is used to filter annotations for InjectionPoint metadata
Expand Down Expand Up @@ -107,6 +108,7 @@ private BeanProcessor(Builder builder) {
applicationClassPredicate);
this.generateSources = builder.generateSources;
this.allowMocking = builder.allowMocking;
this.optimizeContexts = builder.optimizeContexts;
this.transformUnproxyableClasses = builder.transformUnproxyableClasses;
this.suppressConditionGenerators = builder.suppressConditionGenerators;

Expand Down Expand Up @@ -189,6 +191,7 @@ public List<Resource> generateResources(ReflectionRegistration reflectionRegistr
// These maps are precomputed and then used in the ComponentsProviderGenerator which is generated first
Map<BeanInfo, String> beanToGeneratedName = new HashMap<>();
Map<ObserverInfo, String> observerToGeneratedName = new HashMap<>();
Map<DotName, String> scopeToGeneratedName = new HashMap<>();

BeanGenerator beanGenerator = new BeanGenerator(annotationLiterals, applicationClassPredicate, privateMembers,
generateSources, refReg, existingClasses, beanToGeneratedName,
Expand Down Expand Up @@ -229,6 +232,13 @@ public List<Resource> generateResources(ReflectionRegistration reflectionRegistr
observerGenerator.precomputeGeneratedName(observer);
}

ContextInstancesGenerator contextInstancesGenerator = new ContextInstancesGenerator(generateSources,
reflectionRegistration, beanDeployment, scopeToGeneratedName);
if (optimizeContexts) {
contextInstancesGenerator.precomputeGeneratedName(BuiltinScope.APPLICATION.getName());
contextInstancesGenerator.precomputeGeneratedName(BuiltinScope.REQUEST.getName());
}

CustomAlterableContextsGenerator alterableContextsGenerator = new CustomAlterableContextsGenerator(generateSources);
List<CustomAlterableContextInfo> alterableContexts = customAlterableContexts.getRegistered();

Expand All @@ -251,7 +261,8 @@ public Collection<Resource> call() throws Exception {
name,
beanDeployment,
beanToGeneratedName,
observerToGeneratedName);
observerToGeneratedName,
scopeToGeneratedName);
}
}));

Expand Down Expand Up @@ -350,6 +361,20 @@ public Collection<Resource> call() throws Exception {
}));
}

if (optimizeContexts) {
// Generate _ApplicationContextInstances
primaryTasks.add(executor.submit(new Callable<Collection<Resource>>() {

@Override
public Collection<Resource> call() throws Exception {
Collection<Resource> resources = new ArrayList<>();
resources.addAll(contextInstancesGenerator.generate(BuiltinScope.APPLICATION.getName()));
resources.addAll(contextInstancesGenerator.generate(BuiltinScope.REQUEST.getName()));
return resources;
}
}));
}

for (Future<Collection<Resource>> future : primaryTasks) {
resources.addAll(future.get());
}
Expand Down Expand Up @@ -419,7 +444,14 @@ public Collection<Resource> call() throws Exception {
name,
beanDeployment,
beanToGeneratedName,
observerToGeneratedName));
observerToGeneratedName,
scopeToGeneratedName));

if (optimizeContexts) {
// Generate _ApplicationContextInstances
resources.addAll(contextInstancesGenerator.generate(BuiltinScope.APPLICATION.getName()));
resources.addAll(contextInstancesGenerator.generate(BuiltinScope.REQUEST.getName()));
}
}

// Generate AnnotationLiterals - at this point all annotation literals must be processed
Expand Down Expand Up @@ -510,6 +542,7 @@ public static class Builder {
boolean failOnInterceptedPrivateMethod;
boolean allowMocking;
boolean strictCompatibility;
boolean optimizeContexts;

AlternativePriorities alternativePriorities;
final List<Predicate<ClassInfo>> excludeTypes;
Expand Down Expand Up @@ -545,6 +578,7 @@ public Builder() {
failOnInterceptedPrivateMethod = false;
allowMocking = false;
strictCompatibility = false;
optimizeContexts = false;

excludeTypes = new ArrayList<>();

Expand Down Expand Up @@ -780,6 +814,16 @@ public Builder setStrictCompatibility(boolean strictCompatibility) {
return this;
}

/**
*
* @param value
* @return self
*/
public Builder setOptimizeContexts(boolean value) {
this.optimizeContexts = value;
return this;
}

/**
* Can be used to compute a priority of an alternative bean. A non-null computed value always
* takes precedence over the priority defined by {@link Priority} or a stereotype.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,11 @@ public ComponentsProviderGenerator(AnnotationLiteralProcessor annotationLiterals
* @param beanDeployment
* @param beanToGeneratedName
* @param observerToGeneratedName
* @param scopeToContextInstances
* @return a collection of resources
*/
Collection<Resource> generate(String name, BeanDeployment beanDeployment, Map<BeanInfo, String> beanToGeneratedName,
Map<ObserverInfo, String> observerToGeneratedName) {
Map<ObserverInfo, String> observerToGeneratedName, Map<DotName, String> scopeToContextInstances) {

ResourceClassOutput classOutput = new ResourceClassOutput(true, generateSources);

Expand Down Expand Up @@ -162,11 +163,25 @@ Collection<Resource> generate(String name, BeanDeployment beanDeployment, Map<Be
getComponents.load(entry.getKey().toString()), nonbindingMembers);
}

ResultHandle contextInstances;
if (scopeToContextInstances.isEmpty()) {
contextInstances = getComponents.invokeStaticMethod(MethodDescriptors.COLLECTIONS_EMPTY_MAP);
} else {
contextInstances = getComponents.newInstance(MethodDescriptor.ofConstructor(HashMap.class));
for (Entry<DotName, String> e : scopeToContextInstances.entrySet()) {
ResultHandle scope = getComponents.loadClass(e.getKey().toString());
ResultHandle supplier = getComponents.invokeStaticMethod(
MethodDescriptor.ofMethod(Components.class, "newContextInstancesSupplier", Supplier.class, Class.class),
getComponents.loadClass(e.getValue()));
getComponents.invokeInterfaceMethod(MethodDescriptors.MAP_PUT, contextInstances, scope, supplier);
}
}

ResultHandle componentsHandle = getComponents.newInstance(
MethodDescriptor.ofConstructor(Components.class, Collection.class, Collection.class, Collection.class,
Set.class, Map.class, Supplier.class, Map.class, Set.class),
Set.class, Map.class, Supplier.class, Map.class, Set.class, Map.class),
beansHandle, observersHandle, contextsHandle, interceptorBindings, transitiveBindingsHandle,
removedBeansSupplier.getInstance(), qualifiersNonbindingMembers, qualifiers);
removedBeansSupplier.getInstance(), qualifiersNonbindingMembers, qualifiers, contextInstances);
getComponents.returnValue(componentsHandle);

// Finally write the bytecode
Expand Down
Loading

0 comments on commit d39f8d5

Please sign in to comment.