Skip to content

Commit

Permalink
Move return exception pool to StaticScope
Browse files Browse the repository at this point in the history
We cannot use a static thread-local because it will root the
entire runtime (at best) and potentially root classloaders and
keep entire applications in memory after they should have been
cleaned up. Moving this to StaticScope has the following
advantages:

* Localize the return jump cache to the point of initiation, the
  scope doing the non-local return.
* Scopes not using return jumps will not use this cache and not
  create any objects.

The lack of synchronization here is intentional; if two threads
race and both create a ThreadLocal for the scope, one will win and
the other will just be collected eventually. There's no particular
need to ensure only one ThreadLocal gets created.
  • Loading branch information
headius committed Dec 5, 2023
1 parent 26c5f4a commit 2a2015d
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 9 deletions.
14 changes: 5 additions & 9 deletions core/src/main/java/org/jruby/ir/runtime/IRReturnJump.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.jruby.ir.runtime;

import org.jruby.exceptions.Unrescuable;
import org.jruby.ir.IRScope;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.DynamicScope;

Expand All @@ -11,20 +10,17 @@ public class IRReturnJump extends IRJump implements Unrescuable {
private Object returnValue;
private boolean inUse = false;

private static final ThreadLocal<IRReturnJump> RETURN_JUMP = new ThreadLocal<>();

private IRReturnJump(StaticScope returnScope, DynamicScope scopeToReturnFrom, Object rv) {
update(returnScope, scopeToReturnFrom, rv);
private IRReturnJump() {
}

public static IRReturnJump create(StaticScope returnScope, DynamicScope scopeToReturnFrom, Object rv) {
IRReturnJump jump = RETURN_JUMP.get();
IRReturnJump jump = returnScope.getReturnJump();
if (jump == null || jump.inUse) {
RETURN_JUMP.set(jump = new IRReturnJump(returnScope, scopeToReturnFrom, rv));
} else {
jump.update(returnScope, scopeToReturnFrom, rv);
returnScope.setReturnJump(jump = new IRReturnJump());
}

jump.update(returnScope, scopeToReturnFrom, rv);

return jump;
}

Expand Down
19 changes: 19 additions & 0 deletions core/src/main/java/org/jruby/parser/StaticScope.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import org.jruby.ir.IRMethod;
import org.jruby.ir.IRScope;
import org.jruby.ir.IRScopeType;
import org.jruby.ir.runtime.IRReturnJump;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.Signature;
Expand Down Expand Up @@ -123,6 +124,8 @@ public class StaticScope implements Serializable {

private volatile Collection<String> ivarNames;

private ThreadLocal<IRReturnJump> returnJump;

public enum Type {
LOCAL, BLOCK, EVAL;

Expand Down Expand Up @@ -741,4 +744,20 @@ private boolean isTopScopeEvals() {

return scope != null && scope.enclosingScope == null;
}

public IRReturnJump getReturnJump() {
return getReturnJumpThreadLocal().get();
}

public void setReturnJump(IRReturnJump rj) {
getReturnJumpThreadLocal().set(rj);
}

private ThreadLocal<IRReturnJump> getReturnJumpThreadLocal() {
ThreadLocal<IRReturnJump> returnJump = this.returnJump;
if (returnJump == null) {
returnJump = this.returnJump = new ThreadLocal<>();
}
return returnJump;
}
}

0 comments on commit 2a2015d

Please sign in to comment.