Skip to content

Commit

Permalink
ArC: replace thread locals with fields in CreationalContextImpl
Browse files Browse the repository at this point in the history
  • Loading branch information
Ladicek committed Apr 5, 2024
1 parent d4c48ce commit 8cae7cb
Show file tree
Hide file tree
Showing 18 changed files with 150 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public Object create(CreationalContext<Object> creationalContext, Map<String, Ob
throw new IllegalStateException("Cannot load required type: " + requiredType);
}

InjectionPoint injectionPoint = InjectionPointProvider.get();
InjectionPoint injectionPoint = InjectionPointProvider.getCurrent(creationalContext);
if (injectionPoint == null) {
throw new IllegalStateException("No current injection point found");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import org.jboss.logging.Logger;

import io.quarkus.arc.Arc;
import io.quarkus.arc.impl.InjectionPointProvider;
import io.quarkus.runtime.ExecutionMode;
import io.quarkus.runtime.annotations.StaticInitSafe;
import io.smallrye.config.SmallRyeConfig;
Expand All @@ -37,7 +36,8 @@ public class ConfigStaticInitCheckInterceptor {

@AroundInvoke
Object aroundInvoke(InvocationContext context) throws Exception {
recordConfigValue(null, configValues);
InjectionPoint injectionPoint = (InjectionPoint) context.getParameters()[0];
recordConfigValue(injectionPoint, configValues);
return context.proceed();
}

Expand All @@ -46,9 +46,6 @@ static void recordConfigValue(InjectionPoint injectionPoint, ConfigStaticInitVal
// No-op for any other execution mode
return;
}
if (injectionPoint == null) {
injectionPoint = InjectionPointProvider.get();
}
if (injectionPoint == null) {
throw new IllegalStateException("No current injection point found");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class RawOptionalClaimCreator implements BeanCreator<Optional<?>> {

@Override
public Optional<?> create(CreationalContext<Optional<?>> creationalContext, Map<String, Object> params) {
InjectionPoint injectionPoint = InjectionPointProvider.get();
InjectionPoint injectionPoint = InjectionPointProvider.getCurrent(creationalContext);
if (injectionPoint == null) {
throw new IllegalStateException("No current injection point found");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1305,24 +1305,41 @@ private ResultHandle newInstanceHandle(BeanInfo bean, ClassCreator beanCreator,
if (Modifier.isPrivate(constructor.flags())) {
privateMembers.add(isApplicationClass,
String.format("Bean constructor %s on %s", constructor, constructor.declaringClass().name()));
ResultHandle paramTypesArray = creator.newArray(Class.class, creator.load(providerHandles.size()));
ResultHandle argsArray = creator.newArray(Object.class, creator.load(providerHandles.size()));
int params = providerHandles.size();
if (providerTypeName.endsWith(DecoratorGenerator.ABSTRACT_IMPL_SUFFIX)) {
params++;
}
ResultHandle paramTypesArray = creator.newArray(Class.class, creator.load(params));
ResultHandle argsArray = creator.newArray(Object.class, creator.load(params));
for (int i = 0; i < injectionPoints.size(); i++) {
creator.writeArrayValue(paramTypesArray, i,
creator.loadClass(injectionPoints.get(i).getType().name().toString()));
creator.writeArrayValue(argsArray, i, providerHandles.get(i));
}
if (providerTypeName.endsWith(DecoratorGenerator.ABSTRACT_IMPL_SUFFIX)) {
creator.writeArrayValue(paramTypesArray, params - 1, creator.loadClass(CreationalContext.class));
creator.writeArrayValue(argsArray, params - 1, createMethod.getMethodParam(0));
}
registration.registerMethod(constructor);
return creator.invokeStaticMethod(MethodDescriptors.REFLECTIONS_NEW_INSTANCE,
creator.loadClass(constructor.declaringClass().name().toString()),
paramTypesArray, argsArray);
} else {
// new SimpleBean(foo)
String[] paramTypes = new String[injectionPoints.size()];
int params = injectionPoints.size();
if (providerTypeName.endsWith(DecoratorGenerator.ABSTRACT_IMPL_SUFFIX)) {
params++;
}
String[] paramTypes = new String[params];
for (ListIterator<InjectionPointInfo> iterator = injectionPoints.listIterator(); iterator.hasNext();) {
InjectionPointInfo injectionPoint = iterator.next();
paramTypes[iterator.previousIndex()] = DescriptorUtils.typeToString(injectionPoint.getType());
}
if (providerTypeName.endsWith(DecoratorGenerator.ABSTRACT_IMPL_SUFFIX)) {
paramTypes[params - 1] = CreationalContext.class.getName();
providerHandles = new ArrayList<>(providerHandles);
providerHandles.add(createMethod.getMethodParam(0));
}
return creator.newInstance(MethodDescriptor.ofConstructor(providerTypeName, paramTypes),
providerHandles.toArray(new ResultHandle[0]));
}
Expand All @@ -1332,16 +1349,34 @@ private ResultHandle newInstanceHandle(BeanInfo bean, ClassCreator beanCreator,
privateMembers.add(isApplicationClass,
String.format("Bean constructor %s on %s", noArgsConstructor,
noArgsConstructor.declaringClass().name()));
ResultHandle paramTypesArray = creator.newArray(Class.class, creator.load(0));
ResultHandle argsArray = creator.newArray(Object.class, creator.load(0));
ResultHandle paramTypesArray;
ResultHandle argsArray;
if (providerTypeName.endsWith(DecoratorGenerator.ABSTRACT_IMPL_SUFFIX)) {
paramTypesArray = creator.newArray(Class.class, 1);
argsArray = creator.newArray(Object.class, 1);
creator.writeArrayValue(paramTypesArray, 0, creator.loadClass(CreationalContext.class));
creator.writeArrayValue(argsArray, 0, createMethod.getMethodParam(0));
} else {
paramTypesArray = creator.newArray(Class.class, 0);
argsArray = creator.newArray(Object.class, 0);
}

registration.registerMethod(noArgsConstructor);
return creator.invokeStaticMethod(MethodDescriptors.REFLECTIONS_NEW_INSTANCE,
creator.loadClass(noArgsConstructor.declaringClass().name().toString()), paramTypesArray,
argsArray);
} else {
Object[] paramTypes;
ResultHandle[] args;
if (providerTypeName.endsWith(DecoratorGenerator.ABSTRACT_IMPL_SUFFIX)) {
paramTypes = new Object[] { CreationalContext.class };
args = new ResultHandle[] { createMethod.getMethodParam(0) };
} else {
paramTypes = new Object[0];
args = new ResultHandle[0];
}
// new SimpleBean()
return creator.newInstance(MethodDescriptor.ofConstructor(providerTypeName));
return creator.newInstance(MethodDescriptor.ofConstructor(providerTypeName, paramTypes), args);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
Expand All @@ -16,6 +17,8 @@
import java.util.function.Predicate;
import java.util.function.Supplier;

import jakarta.enterprise.context.spi.CreationalContext;

import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
Expand Down Expand Up @@ -171,8 +174,13 @@ private String generateDecoratorImplementation(String baseName, String targetPac

// Constructor
MethodInfo decoratorConstructor = decoratorClass.firstMethod(Methods.INIT);
List<String> decoratorConstructorParams = new ArrayList<>();
for (org.jboss.jandex.Type parameterType : decoratorConstructor.parameterTypes()) {
decoratorConstructorParams.add(parameterType.name().toString());
}
decoratorConstructorParams.add(CreationalContext.class.getName());
MethodCreator constructor = decoratorImplCreator.getMethodCreator(Methods.INIT, "V",
decoratorConstructor.parameterTypes().stream().map(it -> it.name().toString()).toArray());
decoratorConstructorParams.toArray(new Object[0]));
ResultHandle[] constructorArgs = new ResultHandle[decoratorConstructor.parametersCount()];
for (int i = 0; i < decoratorConstructor.parametersCount(); i++) {
constructorArgs[i] = constructor.getMethodParam(i);
Expand All @@ -181,7 +189,8 @@ private String generateDecoratorImplementation(String baseName, String targetPac
constructor.invokeSpecialMethod(decoratorConstructor, constructor.getThis(), constructorArgs);
// Set the delegate field
constructor.writeInstanceField(delegateField.getFieldDescriptor(), constructor.getThis(),
constructor.invokeStaticMethod(MethodDescriptors.DECORATOR_DELEGATE_PROVIDER_GET));
constructor.invokeStaticMethod(MethodDescriptors.DECORATOR_DELEGATE_PROVIDER_GET,
constructor.getMethodParam(decoratorConstructor.parametersCount())));
constructor.returnValue(null);

// Find non-decorated methods from all decorated types
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,14 +287,11 @@ public final class MethodDescriptors {
public static final MethodDescriptor CLIENT_PROXIES_GET_DELEGATE = MethodDescriptor.ofMethod(ClientProxies.class,
"getDelegate", Object.class, InjectableBean.class);

public static final MethodDescriptor DECORATOR_DELEGATE_PROVIDER_SET = MethodDescriptor
.ofMethod(DecoratorDelegateProvider.class, "set", Object.class, Object.class);
public static final MethodDescriptor DECORATOR_DELEGATE_PROVIDER_GET = MethodDescriptor.ofMethod(
DecoratorDelegateProvider.class, "getCurrent", Object.class, CreationalContext.class);

public static final MethodDescriptor DECORATOR_DELEGATE_PROVIDER_UNSET = MethodDescriptor
.ofMethod(DecoratorDelegateProvider.class, "unset", void.class);

public static final MethodDescriptor DECORATOR_DELEGATE_PROVIDER_GET = MethodDescriptor
.ofMethod(DecoratorDelegateProvider.class, "get", Object.class);
public static final MethodDescriptor DECORATOR_DELEGATE_PROVIDER_SET = MethodDescriptor.ofMethod(
DecoratorDelegateProvider.class, "setCurrent", Object.class, CreationalContext.class, Object.class);

public static final MethodDescriptor INSTANCES_LIST_OF = MethodDescriptor
.ofMethod(Instances.class, "listOf", List.class, InjectableBean.class, Type.class, Type.class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -817,12 +817,14 @@ && isDecorated(decoratedMethodDescriptors, methodDescriptor, resolvedMethodDescr
}
ResultHandle delegateSubclassInstance = subclassConstructor.newInstance(MethodDescriptor.ofConstructor(
delegateSubclass.getClassName(), constructorParameterTypes.toArray(new String[0])), paramHandles);
subclassConstructor.invokeStaticMethod(MethodDescriptors.DECORATOR_DELEGATE_PROVIDER_SET, delegateSubclassInstance);
ResultHandle prev = subclassConstructor.invokeStaticMethod(
MethodDescriptors.DECORATOR_DELEGATE_PROVIDER_SET, creationalContext, delegateSubclassInstance);

ResultHandle decoratorInstance = subclassConstructor.invokeInterfaceMethod(
MethodDescriptors.INJECTABLE_REF_PROVIDER_GET, constructorMethodParam, creationalContext);
// And unset the delegate IP afterwards
subclassConstructor.invokeStaticMethod(MethodDescriptors.DECORATOR_DELEGATE_PROVIDER_UNSET);
subclassConstructor.invokeStaticMethod(
MethodDescriptors.DECORATOR_DELEGATE_PROVIDER_SET, creationalContext, prev);

decoratorToResultHandle.put(decorator.getIdentifier(), decoratorInstance);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -553,14 +553,14 @@ static <T> InstanceHandle<T> beanInstanceHandle(InjectableBean<T> bean, Creation
}
InjectionPoint prev = null;
if (resetCurrentInjectionPoint) {
prev = InjectionPointProvider.set(CurrentInjectionPointProvider.EMPTY);
prev = InjectionPointProvider.setCurrent(creationalContext, CurrentInjectionPointProvider.EMPTY);
}
try {
return new EagerInstanceHandle<>(bean, bean.get(creationalContext), creationalContext, parentContext,
destroyLogic);
} finally {
if (resetCurrentInjectionPoint) {
InjectionPointProvider.set(prev);
InjectionPointProvider.setCurrent(creationalContext, prev);
}
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ public Object getReference(Bean<?> bean, Type beanType, CreationalContext<?> ctx
if (bean instanceof InjectableBean && ctx instanceof CreationalContextImpl) {
// there's no actual injection point or an `Instance` object,
// the "current" injection point must be `null`
InjectionPoint prev = InjectionPointProvider.set(null);
InjectionPoint prev = InjectionPointProvider.setCurrent(ctx, null);
try {
return ArcContainerImpl.beanInstanceHandle((InjectableBean) bean, (CreationalContextImpl) ctx,
false, null, true).get();
} finally {
InjectionPointProvider.set(prev);
InjectionPointProvider.setCurrent(ctx, prev);
}
}
throw new IllegalArgumentException(
Expand All @@ -86,12 +86,12 @@ public Object getInjectableReference(InjectionPoint ij, CreationalContext<?> ctx
throw new UnsatisfiedResolutionException();
}
InjectableBean<?> bean = (InjectableBean<?>) resolve(beans);
InjectionPoint prev = InjectionPointProvider.set(ij);
InjectionPoint prev = InjectionPointProvider.setCurrent(ctx, ij);
try {
return ArcContainerImpl.beanInstanceHandle(bean, (CreationalContextImpl) ctx,
false, null, true).get();
} finally {
InjectionPointProvider.set(prev);
InjectionPointProvider.setCurrent(ctx, prev);
}
}
throw new IllegalArgumentException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import jakarta.enterprise.context.spi.Contextual;
import jakarta.enterprise.context.spi.CreationalContext;
import jakarta.enterprise.inject.spi.InjectionPoint;

import io.quarkus.arc.InjectableBean;
import io.quarkus.arc.InjectableReferenceProvider;
Expand All @@ -24,6 +25,9 @@ public class CreationalContextImpl<T> implements CreationalContext<T>, Function<
private final CreationalContextImpl<?> parent;
private List<InstanceHandle<?>> dependentInstances;

private InjectionPoint currentInjectionPoint;
private Object currentDecoratorDelegate;

public CreationalContextImpl(Contextual<T> contextual) {
this(contextual, null);
}
Expand Down Expand Up @@ -129,4 +133,50 @@ public static <I> void addDependencyToParent(InjectableBean<I> bean, I instance,
}
}

static <T> InjectionPoint getCurrentInjectionPoint(CreationalContext<T> ctx) {
CreationalContextImpl<?> instance = unwrap(ctx);
while (instance != null) {
synchronized (instance) {
InjectionPoint result = instance.currentInjectionPoint;
if (result != null) {
return result;
}
}
instance = instance.parent;
}
return null;
}

static <T> InjectionPoint setCurrentInjectionPoint(CreationalContext<T> ctx, InjectionPoint injectionPoint) {
CreationalContextImpl<T> instance = unwrap(ctx);
synchronized (instance) {
InjectionPoint previous = instance.currentInjectionPoint;
instance.currentInjectionPoint = injectionPoint;
return previous;
}
}

static <T> Object getCurrentDecoratorDelegate(CreationalContext<T> ctx) {
CreationalContextImpl<?> instance = unwrap(ctx);
while (instance != null) {
synchronized (instance) {
Object result = instance.currentDecoratorDelegate;
if (result != null) {
return result;
}
}
instance = instance.parent;
}
return null;
}

static <T> Object setCurrentDecoratorDelegate(CreationalContext<T> ctx, Object decoratorDelegate) {
CreationalContextImpl<T> instance = unwrap(ctx);
synchronized (instance) {
Object previous = instance.currentDecoratorDelegate;
instance.currentDecoratorDelegate = decoratorDelegate;
return previous;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ public CurrentInjectionPointProvider(InjectableBean<?> bean, Supplier<Injectable

@Override
public T get(CreationalContext<T> creationalContext) {
InjectionPoint prev = InjectionPointProvider.set(injectionPoint);
InjectionPoint prev = InjectionPointProvider.setCurrent(creationalContext, injectionPoint);
try {
return delegateSupplier.get().get(creationalContext);
} finally {
InjectionPointProvider.set(prev);
InjectionPointProvider.setCurrent(creationalContext, prev);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,22 @@

public class DecoratorDelegateProvider implements InjectableReferenceProvider<Object> {

private static final ThreadLocal<Object> CURRENT = new ThreadLocal<>();

@Override
public Object get(CreationalContext<Object> creationalContext) {
return CURRENT.get();
return getCurrent(creationalContext);
}

public static Object getCurrent(CreationalContext<?> ctx) {
return CreationalContextImpl.getCurrentDecoratorDelegate(ctx);
}

/**
* Set the current delegate for a non-null parameter, remove the threadlocal for null parameter.
* Set the current delegate for a non-null parameter, or remove it for null parameter.
*
* @param delegate
* @return the previous delegate or {@code null}
*/
public static Object set(Object delegate) {
if (delegate != null) {
Object prev = CURRENT.get();
if (delegate.equals(prev)) {
return delegate;
} else {
CURRENT.set(delegate);
return prev;
}
} else {
CURRENT.remove();
return null;
}
}

public static void unset() {
set(null);
}

public static Object get() {
return CURRENT.get();
public static Object setCurrent(CreationalContext<?> ctx, Object delegate) {
return CreationalContextImpl.setCurrentDecoratorDelegate(ctx, delegate);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public Set<Type> getTypes() {
@Override
public Event<?> get(CreationalContext<Event<?>> creationalContext) {
// Obtain current IP to get the required type and qualifiers
InjectionPoint ip = InjectionPointProvider.get();
InjectionPoint ip = InjectionPointProvider.getCurrent(creationalContext);
return new EventImpl<>(ip.getType(), ip.getQualifiers(), ip);
}

Expand Down
Loading

0 comments on commit 8cae7cb

Please sign in to comment.