Skip to content

[GR-18163] Cache Method#to_proc result's call target in global cache #3540

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 11 additions & 27 deletions src/main/java/org/truffleruby/core/method/MethodNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -285,30 +285,18 @@ RubyUnboundMethod unbind(RubyMethod method,
@CoreMethod(names = "to_proc")
public abstract static class ToProcNode extends CoreMethodArrayArgumentsNode {

@Specialization(guards = { "isSingleContext()", "methodObject == cachedMethodObject" },
limit = "getCacheLimit()")
RubyProc toProcCachedSingleContext(RubyMethod methodObject,
@Cached("methodObject") RubyMethod cachedMethodObject,
@Cached("toProcUncached(cachedMethodObject)") RubyProc proc) {
return proc;
}

@Specialization(
guards = "methodObject.method.getCallTarget() == methodCallTarget",
limit = "getCacheLimit()",
replaces = "toProcCachedSingleContext")
RubyProc toProcCachedTarget(RubyMethod methodObject,
@Cached("methodObject.method.getCallTarget()") RootCallTarget methodCallTarget,
@Cached("procCallTargetToCallRubyMethod(methodCallTarget)") RootCallTarget procCallTarget) {
return createProc(procCallTarget, methodObject.method, methodObject.receiver);
}

@Specialization(replaces = { "toProcCachedSingleContext", "toProcCachedTarget" })
RubyProc toProcUncached(RubyMethod methodObject) {
@Specialization
RubyProc toProc(RubyMethod methodObject) {
final InternalMethod method = methodObject.method;
final Object receiver = methodObject.receiver;
final RootCallTarget callTarget = procCallTargetToCallRubyMethod(method.getCallTarget());
return createProc(callTarget, method, receiver);
RootCallTarget toProcCallTarget = method.toProcCallTarget;

if (toProcCallTarget == null) {
toProcCallTarget = createToProcCallTarget(method.getCallTarget());
method.toProcCallTarget = toProcCallTarget;
}

return createProc(toProcCallTarget, method, receiver);
}

private RubyProc createProc(RootCallTarget callTarget, InternalMethod method, Object receiver) {
Expand All @@ -331,7 +319,7 @@ private RubyProc createProc(RootCallTarget callTarget, InternalMethod method, Ob
}

@TruffleBoundary
protected RootCallTarget procCallTargetToCallRubyMethod(RootCallTarget callTarget) {
protected RootCallTarget createToProcCallTarget(RootCallTarget callTarget) {
// translate to something like:
// lambda { |same args list| method.call(args) }
// We need to preserve the method receiver and we want to have the same argument list.
Expand All @@ -354,10 +342,6 @@ protected RootCallTarget procCallTargetToCallRubyMethod(RootCallTarget callTarge
return wrapRootNode.getCallTarget();
}

protected int getCacheLimit() {
return getLanguage().options.METHOD_TO_PROC_CACHE;
}

private static final class CallWithRubyMethodReceiverNode extends RubyContextSourceNode {
@Child private CallInternalMethodNode callInternalMethodNode = CallInternalMethodNode.create();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ public final class InternalMethod implements ObjectGraphNode {
private final CachedLazyCallTargetSupplier callTargetSupplier;
@CompilationFinal private RootCallTarget callTarget;

/** call target of a Proc created from a method and cached for consequent Method#to_proc calls */
public RootCallTarget toProcCallTarget;

public static InternalMethod fromProc(
RubyContext context,
SharedMethodInfo sharedMethodInfo,
Expand Down
13 changes: 0 additions & 13 deletions src/main/java/org/truffleruby/options/LanguageOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ public final class LanguageOptions {
public final int DISPATCH_CACHE;
/** --yield-cache=DEFAULT_CACHE */
public final int YIELD_CACHE;
/** --to-proc-cache=DEFAULT_CACHE */
public final int METHOD_TO_PROC_CACHE;
/** --is-a-cache=DEFAULT_CACHE */
public final int IS_A_CACHE;
/** --bind-cache=DEFAULT_CACHE */
Expand Down Expand Up @@ -156,7 +154,6 @@ public LanguageOptions(Env env, OptionValues options, boolean singleContext) {
METHOD_LOOKUP_CACHE = options.hasBeenSet(OptionsCatalog.METHOD_LOOKUP_CACHE_KEY) ? options.get(OptionsCatalog.METHOD_LOOKUP_CACHE_KEY) : DEFAULT_CACHE;
DISPATCH_CACHE = options.hasBeenSet(OptionsCatalog.DISPATCH_CACHE_KEY) ? options.get(OptionsCatalog.DISPATCH_CACHE_KEY) : DEFAULT_CACHE;
YIELD_CACHE = options.hasBeenSet(OptionsCatalog.YIELD_CACHE_KEY) ? options.get(OptionsCatalog.YIELD_CACHE_KEY) : DEFAULT_CACHE;
METHOD_TO_PROC_CACHE = options.hasBeenSet(OptionsCatalog.METHOD_TO_PROC_CACHE_KEY) ? options.get(OptionsCatalog.METHOD_TO_PROC_CACHE_KEY) : DEFAULT_CACHE;
IS_A_CACHE = options.hasBeenSet(OptionsCatalog.IS_A_CACHE_KEY) ? options.get(OptionsCatalog.IS_A_CACHE_KEY) : DEFAULT_CACHE;
BIND_CACHE = options.hasBeenSet(OptionsCatalog.BIND_CACHE_KEY) ? options.get(OptionsCatalog.BIND_CACHE_KEY) : DEFAULT_CACHE;
CONSTANT_CACHE = options.hasBeenSet(OptionsCatalog.CONSTANT_CACHE_KEY) ? options.get(OptionsCatalog.CONSTANT_CACHE_KEY) : DEFAULT_CACHE;
Expand Down Expand Up @@ -237,8 +234,6 @@ public Object fromDescriptor(OptionDescriptor descriptor) {
return DISPATCH_CACHE;
case "ruby.yield-cache":
return YIELD_CACHE;
case "ruby.to-proc-cache":
return METHOD_TO_PROC_CACHE;
case "ruby.is-a-cache":
return IS_A_CACHE;
case "ruby.bind-cache":
Expand Down Expand Up @@ -328,7 +323,6 @@ public static boolean areOptionsCompatible(OptionValues one, OptionValues two) {
one.get(OptionsCatalog.METHOD_LOOKUP_CACHE_KEY).equals(two.get(OptionsCatalog.METHOD_LOOKUP_CACHE_KEY)) &&
one.get(OptionsCatalog.DISPATCH_CACHE_KEY).equals(two.get(OptionsCatalog.DISPATCH_CACHE_KEY)) &&
one.get(OptionsCatalog.YIELD_CACHE_KEY).equals(two.get(OptionsCatalog.YIELD_CACHE_KEY)) &&
one.get(OptionsCatalog.METHOD_TO_PROC_CACHE_KEY).equals(two.get(OptionsCatalog.METHOD_TO_PROC_CACHE_KEY)) &&
one.get(OptionsCatalog.IS_A_CACHE_KEY).equals(two.get(OptionsCatalog.IS_A_CACHE_KEY)) &&
one.get(OptionsCatalog.BIND_CACHE_KEY).equals(two.get(OptionsCatalog.BIND_CACHE_KEY)) &&
one.get(OptionsCatalog.CONSTANT_CACHE_KEY).equals(two.get(OptionsCatalog.CONSTANT_CACHE_KEY)) &&
Expand Down Expand Up @@ -526,13 +520,6 @@ public static boolean areOptionsCompatibleOrLog(TruffleLogger logger, LanguageOp
return false;
}

oldValue = oldOptions.METHOD_TO_PROC_CACHE;
newValue = newOptions.METHOD_TO_PROC_CACHE;
if (!newValue.equals(oldValue)) {
logger.fine("not reusing pre-initialized context: --to-proc-cache differs, was: " + oldValue + " and is now: " + newValue);
return false;
}

oldValue = oldOptions.IS_A_CACHE;
newValue = newOptions.IS_A_CACHE;
if (!newValue.equals(oldValue)) {
Expand Down
2 changes: 0 additions & 2 deletions src/options.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ LANGUAGE_OPTIONS:
- METHOD_LOOKUP_CACHE
- DISPATCH_CACHE
- YIELD_CACHE
- METHOD_TO_PROC_CACHE
- IS_A_CACHE
- BIND_CACHE
- CONSTANT_CACHE
Expand Down Expand Up @@ -201,7 +200,6 @@ INTERNAL: # Options for debugging the TruffleRuby implementation
METHOD_LOOKUP_CACHE: [method-lookup-cache, integer, DEFAULT_CACHE, Method lookup cache size]
DISPATCH_CACHE: [dispatch-cache, integer, DEFAULT_CACHE, Dispatch (various forms of method call) cache size]
YIELD_CACHE: [yield-cache, integer, DEFAULT_CACHE, Yield cache size]
METHOD_TO_PROC_CACHE: [to-proc-cache, integer, DEFAULT_CACHE, Method#to_proc cache size]
IS_A_CACHE: [is-a-cache, integer, DEFAULT_CACHE, 'Kernel#is_a? and #kind_of? cache size']
BIND_CACHE: [bind-cache, integer, DEFAULT_CACHE, Cache size of test for being able to bind a method to a module]
CONSTANT_CACHE: [constant-cache, integer, DEFAULT_CACHE, Constant cache size]
Expand Down
12 changes: 0 additions & 12 deletions src/shared/java/org/truffleruby/shared/options/OptionsCatalog.java
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ public final class OptionsCatalog {
public static final OptionKey<Integer> METHOD_LOOKUP_CACHE_KEY = new OptionKey<>(DEFAULT_CACHE_KEY.getDefaultValue());
public static final OptionKey<Integer> DISPATCH_CACHE_KEY = new OptionKey<>(DEFAULT_CACHE_KEY.getDefaultValue());
public static final OptionKey<Integer> YIELD_CACHE_KEY = new OptionKey<>(DEFAULT_CACHE_KEY.getDefaultValue());
public static final OptionKey<Integer> METHOD_TO_PROC_CACHE_KEY = new OptionKey<>(DEFAULT_CACHE_KEY.getDefaultValue());
public static final OptionKey<Integer> IS_A_CACHE_KEY = new OptionKey<>(DEFAULT_CACHE_KEY.getDefaultValue());
public static final OptionKey<Integer> BIND_CACHE_KEY = new OptionKey<>(DEFAULT_CACHE_KEY.getDefaultValue());
public static final OptionKey<Integer> CONSTANT_CACHE_KEY = new OptionKey<>(DEFAULT_CACHE_KEY.getDefaultValue());
Expand Down Expand Up @@ -925,14 +924,6 @@ public final class OptionsCatalog {
.usageSyntax("8")
.build();

public static final OptionDescriptor METHOD_TO_PROC_CACHE = OptionDescriptor
.newBuilder(METHOD_TO_PROC_CACHE_KEY, "ruby.to-proc-cache")
.help("Method#to_proc cache size")
.category(OptionCategory.INTERNAL)
.stability(OptionStability.EXPERIMENTAL)
.usageSyntax("8")
.build();

public static final OptionDescriptor IS_A_CACHE = OptionDescriptor
.newBuilder(IS_A_CACHE_KEY, "ruby.is-a-cache")
.help("Kernel#is_a? and #kind_of? cache size")
Expand Down Expand Up @@ -1509,8 +1500,6 @@ public static OptionDescriptor fromName(String name) {
return DISPATCH_CACHE;
case "ruby.yield-cache":
return YIELD_CACHE;
case "ruby.to-proc-cache":
return METHOD_TO_PROC_CACHE;
case "ruby.is-a-cache":
return IS_A_CACHE;
case "ruby.bind-cache":
Expand Down Expand Up @@ -1709,7 +1698,6 @@ public static OptionDescriptor[] allDescriptors() {
METHOD_LOOKUP_CACHE,
DISPATCH_CACHE,
YIELD_CACHE,
METHOD_TO_PROC_CACHE,
IS_A_CACHE,
BIND_CACHE,
CONSTANT_CACHE,
Expand Down
Loading