-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
according to https://rules.sonarsource.com/java/tag/leak/RSPEC-5164/. Now, there no longer is a thread-local stack of AroundClosure instances, but rather a list of them, which can only grow but never shrink. Instead, we now have a thread-local (integer) list index, for every thread being initialised with pointing to the last element. I.e., every thread can unwind by decrementing the index while proceeding, independently of other threads. A positive side effect is that this approach also works for long-lived threads from thread pools, used by executor services. Hence, test Bugs199Tests.testAsyncProceedNestedAroundAdviceThreadPool_gh128, which was previously commented out, has been activated and passes, see #141. I am not sure if this brings @AspectJ style, non-inlined, nested around advice execution functionally on par with native ones, but at least for current scenarios it seems to work. Fixes #288, #141. Signed-off-by: Alexander Kriegisch <[email protected]>
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,14 +13,15 @@ | |
|
||
package org.aspectj.runtime.reflect; | ||
|
||
import java.util.Stack; | ||
|
||
import org.aspectj.lang.JoinPoint; | ||
import org.aspectj.lang.ProceedingJoinPoint; | ||
import org.aspectj.lang.Signature; | ||
import org.aspectj.lang.reflect.SourceLocation; | ||
import org.aspectj.runtime.internal.AroundClosure; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
class JoinPointImpl implements ProceedingJoinPoint { | ||
static class StaticPartImpl implements JoinPoint.StaticPart { | ||
String kind; | ||
|
@@ -79,18 +80,6 @@ public EnclosingStaticPartImpl(int count, String kind, Signature signature, Sour | |
} | ||
} | ||
|
||
static class InheritableThreadLocalAroundClosureStack extends InheritableThreadLocal<Stack<AroundClosure>> { | ||
@Override | ||
protected Stack<AroundClosure> initialValue() { | ||
return new Stack<>(); | ||
} | ||
|
||
@Override | ||
protected Stack<AroundClosure> childValue(Stack<AroundClosure> parentValue) { | ||
return (Stack<AroundClosure>) parentValue.clone(); | ||
} | ||
} | ||
|
||
Object _this; | ||
Object target; | ||
Object[] args; | ||
|
@@ -152,23 +141,26 @@ public final String toLongString() { | |
// will either be using arc or arcs but not both. arcs being non-null | ||
// indicates it is in use (even if an empty stack) | ||
private AroundClosure arc = null; | ||
private InheritableThreadLocalAroundClosureStack arcs = null; | ||
private List<AroundClosure> arcs = null; | ||
private final ThreadLocal<Integer> arcIndex = ThreadLocal.withInitial(() -> arcs == null ? -1 : arcs.size() - 1); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
KimmingLau
Contributor
|
||
|
||
public void set$AroundClosure(AroundClosure arc) { | ||
this.arc = arc; | ||
} | ||
|
||
public void stack$AroundClosure(AroundClosure arc) { | ||
public void stack$AroundClosure(AroundClosure arc) { | ||
// If input parameter arc is null this is the 'unlink' call from AroundClosure | ||
if (arcs == null) { | ||
arcs = new InheritableThreadLocalAroundClosureStack(); | ||
arcs = new ArrayList<>(); | ||
} | ||
if (arc==null) { | ||
this.arcs.get().pop(); | ||
} else { | ||
this.arcs.get().push(arc); | ||
if (arc == null) { | ||
arcIndex.set(arcIndex.get() - 1); | ||
} | ||
else { | ||
this.arcs.add(arc); | ||
arcIndex.set(arcs.size() - 1); | ||
} | ||
} | ||
} | ||
|
||
public Object proceed() throws Throwable { | ||
// when called from a before advice, but be a no-op | ||
|
@@ -179,19 +171,14 @@ public Object proceed() throws Throwable { | |
return arc.run(arc.getState()); | ||
} | ||
} else { | ||
final AroundClosure ac = arcs.get().peek(); | ||
final AroundClosure ac = arcs.get(arcIndex.get()); | ||
return ac.run(ac.getState()); | ||
} | ||
} | ||
|
||
public Object proceed(Object[] adviceBindings) throws Throwable { | ||
// when called from a before advice, but be a no-op | ||
AroundClosure ac = null; | ||
if (arcs == null) { | ||
ac = arc; | ||
} else { | ||
ac = arcs.get().peek(); | ||
} | ||
AroundClosure ac = arcs == null ? arc : arcs.get(arcIndex.get()); | ||
|
||
if (ac == null) { | ||
return null; | ||
|
Hi, I think here is a problem that after JoinPointImpl object was clean up by GC, the entry of ThreadLocalMap will not be released in time, because entry is WeakReference. Shall we consider proactive removing the ThreadLocal of arcIndex?