From 1bbf062dc801f7b4ae556f0d8918c4c0f0111e0d Mon Sep 17 00:00:00 2001 From: Andrew Konchin Date: Fri, 12 Apr 2024 17:45:24 +0300 Subject: [PATCH 1/2] Cache Method#to_proc result's call target in global cache --- .../truffleruby/core/method/MethodNodes.java | 38 ++++++------------- .../language/methods/InternalMethod.java | 3 ++ 2 files changed, 14 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/truffleruby/core/method/MethodNodes.java b/src/main/java/org/truffleruby/core/method/MethodNodes.java index cd3a78490b1d..d90c866a8460 100644 --- a/src/main/java/org/truffleruby/core/method/MethodNodes.java +++ b/src/main/java/org/truffleruby/core/method/MethodNodes.java @@ -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) { @@ -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. @@ -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(); diff --git a/src/main/java/org/truffleruby/language/methods/InternalMethod.java b/src/main/java/org/truffleruby/language/methods/InternalMethod.java index 90ecf43feac0..26ddae91daef 100644 --- a/src/main/java/org/truffleruby/language/methods/InternalMethod.java +++ b/src/main/java/org/truffleruby/language/methods/InternalMethod.java @@ -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, From 61f1f766bb57d3358f920d9a9995fd9814a6c5cb Mon Sep 17 00:00:00 2001 From: Andrew Konchin Date: Mon, 15 Apr 2024 15:07:41 +0300 Subject: [PATCH 2/2] Remove not used --to-proc-cache option --- .../org/truffleruby/options/LanguageOptions.java | 13 ------------- src/options.yml | 2 -- .../truffleruby/shared/options/OptionsCatalog.java | 12 ------------ 3 files changed, 27 deletions(-) diff --git a/src/main/java/org/truffleruby/options/LanguageOptions.java b/src/main/java/org/truffleruby/options/LanguageOptions.java index 610fa8d4bd4f..47296b0813ba 100644 --- a/src/main/java/org/truffleruby/options/LanguageOptions.java +++ b/src/main/java/org/truffleruby/options/LanguageOptions.java @@ -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 */ @@ -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; @@ -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": @@ -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)) && @@ -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)) { diff --git a/src/options.yml b/src/options.yml index b5645fcbb0d5..05c960135b8e 100644 --- a/src/options.yml +++ b/src/options.yml @@ -28,7 +28,6 @@ LANGUAGE_OPTIONS: - METHOD_LOOKUP_CACHE - DISPATCH_CACHE - YIELD_CACHE -- METHOD_TO_PROC_CACHE - IS_A_CACHE - BIND_CACHE - CONSTANT_CACHE @@ -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] diff --git a/src/shared/java/org/truffleruby/shared/options/OptionsCatalog.java b/src/shared/java/org/truffleruby/shared/options/OptionsCatalog.java index 35845d1e090f..c1213f376775 100644 --- a/src/shared/java/org/truffleruby/shared/options/OptionsCatalog.java +++ b/src/shared/java/org/truffleruby/shared/options/OptionsCatalog.java @@ -115,7 +115,6 @@ public final class OptionsCatalog { public static final OptionKey METHOD_LOOKUP_CACHE_KEY = new OptionKey<>(DEFAULT_CACHE_KEY.getDefaultValue()); public static final OptionKey DISPATCH_CACHE_KEY = new OptionKey<>(DEFAULT_CACHE_KEY.getDefaultValue()); public static final OptionKey YIELD_CACHE_KEY = new OptionKey<>(DEFAULT_CACHE_KEY.getDefaultValue()); - public static final OptionKey METHOD_TO_PROC_CACHE_KEY = new OptionKey<>(DEFAULT_CACHE_KEY.getDefaultValue()); public static final OptionKey IS_A_CACHE_KEY = new OptionKey<>(DEFAULT_CACHE_KEY.getDefaultValue()); public static final OptionKey BIND_CACHE_KEY = new OptionKey<>(DEFAULT_CACHE_KEY.getDefaultValue()); public static final OptionKey CONSTANT_CACHE_KEY = new OptionKey<>(DEFAULT_CACHE_KEY.getDefaultValue()); @@ -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") @@ -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": @@ -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,