Skip to content

Commit

Permalink
Zero-Garbage ContextInstances::forEach
Browse files Browse the repository at this point in the history
  • Loading branch information
franz1981 authored and mkouba committed Jan 5, 2024
1 parent 9bca238 commit 5ae4d99
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 7 deletions.
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 static org.objectweb.asm.Opcodes.ACC_VOLATILE;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
Expand All @@ -13,6 +14,7 @@
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Supplier;

import org.jboss.jandex.DotName;
Expand Down Expand Up @@ -88,7 +90,7 @@ Collection<Resource> generate(DotName scope) {
implementRemove(contextInstances, beans, idToField, lockField.getFieldDescriptor());
implementClear(contextInstances, idToField, lockField.getFieldDescriptor());
implementGetAllPresent(contextInstances, idToField, lockField.getFieldDescriptor());

implementForEach(contextInstances, idToField, lockField.getFieldDescriptor());
contextInstances.close();

return classOutput.getResources();
Expand Down Expand Up @@ -149,6 +151,31 @@ private void implementClear(ClassCreator applicationContextInstances, Map<String
catchBlock.throwException(catchBlock.getCaughtException());
}

private void implementForEach(ClassCreator contextInstances, Map<String, FieldDescriptor> idToField,
FieldDescriptor lockField) {
MethodCreator forEach = contextInstances.getMethodCreator("forEach", void.class, Consumer.class)
.setModifiers(ACC_PUBLIC);
// lock.lock();
// ContextInstanceHandle<?> copy = this.1;
// lock.unlock();
// if (copy != null) {
// consumer.accept(copy);
// }
ResultHandle lock = forEach.readInstanceField(lockField, forEach.getThis());
forEach.invokeInterfaceMethod(MethodDescriptors.LOCK_LOCK, lock);
List<ResultHandle> results = new ArrayList<>(idToField.size());
for (FieldDescriptor field : idToField.values()) {
results.add(forEach.readInstanceField(field, forEach.getThis()));
}
forEach.invokeInterfaceMethod(MethodDescriptors.LOCK_UNLOCK, lock);
for (int i = 0; i < results.size(); i++) {
ResultHandle copy = results.get(i);
BytecodeCreator isNotNull = forEach.ifNotNull(copy).trueBranch();
isNotNull.invokeInterfaceMethod(MethodDescriptors.CONSUMER_ACCEPT, forEach.getMethodParam(0), copy);
}
forEach.returnVoid();
}

private void implementRemove(ClassCreator contextInstances, List<BeanInfo> applicationScopedBeans,
Map<String, FieldDescriptor> idToField, FieldDescriptor lockField) {
MethodCreator remove = contextInstances
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

Expand Down Expand Up @@ -63,6 +64,9 @@ public final class MethodDescriptors {

public static final MethodDescriptor SUPPLIER_GET = MethodDescriptor.ofMethod(Supplier.class, "get", Object.class);

public static final MethodDescriptor CONSUMER_ACCEPT = MethodDescriptor.ofMethod(Consumer.class, "accept",
void.class, Object.class);

public static final MethodDescriptor CREATIONAL_CTX_CHILD = MethodDescriptor.ofMethod(CreationalContextImpl.class, "child",
CreationalContextImpl.class,
CreationalContext.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package io.quarkus.arc.impl;

import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -87,7 +84,11 @@ public void destroy(Contextual<?> contextual) {

@Override
public synchronized void destroy() {
Set<ContextInstanceHandle<?>> values = instances.getAllPresent();
List<ContextInstanceHandle<?>> values = new LinkedList<>();
instances.forEach(values::add);
if (values.isEmpty()) {
return;
}
// Destroy the producers first
for (Iterator<ContextInstanceHandle<?>> iterator = values.iterator(); iterator.hasNext();) {
ContextInstanceHandle<?> instanceHandle = iterator.next();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.quarkus.arc.impl;

import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;

import io.quarkus.arc.ContextInstanceHandle;
Expand Down Expand Up @@ -38,4 +39,9 @@ public void clear() {
instances.clear();
}

@Override
public void forEach(Consumer<? super ContextInstanceHandle<?>> handleConsumer) {
instances.getPresentValues().forEach(handleConsumer);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.quarkus.arc.impl;

import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;

import io.quarkus.arc.ContextInstanceHandle;
Expand All @@ -17,4 +18,6 @@ public interface ContextInstances {

void clear();

void forEach(Consumer<? super ContextInstanceHandle<?>> handleConsumer);

}
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ public void destroy(ContextState state) {
if (reqState.invalidate()) {
// Fire an event with qualifier @BeforeDestroyed(RequestScoped.class) if there are any observers for it
fireIfNotEmpty(beforeDestroyedNotifier);
reqState.contextInstances.getAllPresent().forEach(this::destroyContextElement);
reqState.contextInstances.forEach(this::destroyContextElement);
reqState.contextInstances.clear();
// Fire an event with qualifier @Destroyed(RequestScoped.class) if there are any observers for it
fireIfNotEmpty(destroyedNotifier);
Expand Down

0 comments on commit 5ae4d99

Please sign in to comment.