Skip to content

Commit 519e5d6

Browse files
committed
Cache by refinements and not the full DeclarationContext for Symbol#to_proc
1 parent 3d8f326 commit 519e5d6

File tree

2 files changed

+36
-21
lines changed

2 files changed

+36
-21
lines changed

src/main/java/org/truffleruby/core/symbol/RubySymbol.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.truffleruby.RubyLanguage;
1414
import org.truffleruby.core.Hashing;
1515
import org.truffleruby.core.klass.RubyClass;
16+
import org.truffleruby.core.module.RubyModule;
1617
import org.truffleruby.core.proc.RubyProc;
1718
import org.truffleruby.core.rope.Rope;
1819
import org.truffleruby.language.ImmutableRubyObject;
@@ -24,8 +25,8 @@
2425
import com.oracle.truffle.api.interop.TruffleObject;
2526
import com.oracle.truffle.api.library.ExportLibrary;
2627
import com.oracle.truffle.api.library.ExportMessage;
27-
import org.truffleruby.language.methods.DeclarationContext;
2828

29+
import java.util.Map;
2930
import java.util.concurrent.ConcurrentHashMap;
3031
import java.util.concurrent.ConcurrentMap;
3132

@@ -40,7 +41,8 @@ public final class RubySymbol extends ImmutableRubyObject implements TruffleObje
4041
private final Rope rope;
4142
private final int javaStringHashCode;
4243
private final long id;
43-
private final ConcurrentMap<DeclarationContext, RubyProc> cachedProcs = new ConcurrentHashMap<>();
44+
/** refinements -> Proc for Symbol#to_proc */
45+
private final ConcurrentMap<Map<RubyModule, RubyModule[]>, RubyProc> cachedProcs = new ConcurrentHashMap<>();
4446

4547
public RubySymbol(String string, Rope rope, long id) {
4648
this.string = string;
@@ -65,7 +67,7 @@ public Rope getRope() {
6567
return rope;
6668
}
6769

68-
public ConcurrentMap<DeclarationContext, RubyProc> getCachedProcs() {
70+
public ConcurrentMap<Map<RubyModule, RubyModule[]>, RubyProc> getCachedProcs() {
6971
return cachedProcs;
7072
}
7173

src/main/java/org/truffleruby/core/symbol/SymbolNodes.java

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010
package org.truffleruby.core.symbol;
1111

12+
import org.truffleruby.RubyContext;
1213
import org.truffleruby.builtins.CoreMethod;
1314
import org.truffleruby.builtins.CoreMethodArrayArgumentsNode;
1415
import org.truffleruby.builtins.CoreModule;
@@ -17,6 +18,7 @@
1718
import org.truffleruby.core.CoreLibrary;
1819
import org.truffleruby.core.array.RubyArray;
1920
import org.truffleruby.core.klass.RubyClass;
21+
import org.truffleruby.core.module.RubyModule;
2022
import org.truffleruby.core.proc.ProcOperations;
2123
import org.truffleruby.core.proc.ProcType;
2224
import org.truffleruby.core.proc.RubyProc;
@@ -46,6 +48,8 @@
4648
import com.oracle.truffle.api.frame.VirtualFrame;
4749
import com.oracle.truffle.api.source.SourceSection;
4850

51+
import java.util.Map;
52+
4953
@CoreModule(value = "Symbol", isClass = true)
5054
public abstract class SymbolNodes {
5155

@@ -101,34 +105,39 @@ public abstract static class ToProcNode extends CoreMethodArrayArgumentsNode {
101105
@Child private ReadCallerFrameNode readCallerFrame = ReadCallerFrameNode.create();
102106

103107
@Specialization(
104-
guards = { "cachedSymbol == symbol", "getDeclarationContext(frame) == cachedDeclarationContext" },
108+
guards = { "symbol == cachedSymbol", "getRefinements(frame) == cachedRefinements" },
105109
limit = "getIdentityCacheLimit()")
106110
protected RubyProc toProcCached(VirtualFrame frame, RubySymbol symbol,
107111
@Cached("symbol") RubySymbol cachedSymbol,
108-
@Cached("getDeclarationContext(frame)") DeclarationContext cachedDeclarationContext,
109-
@Cached("getOrCreateProc(cachedDeclarationContext, symbol)") RubyProc cachedProc) {
112+
@Cached("getRefinements(frame)") Map<RubyModule, RubyModule[]> cachedRefinements,
113+
@Cached("getOrCreateProc(cachedRefinements, symbol)") RubyProc cachedProc) {
110114
return cachedProc;
111115
}
112116

113117
@Specialization
114118
protected RubyProc toProcUncached(VirtualFrame frame, RubySymbol symbol) {
115-
DeclarationContext declarationContext = getDeclarationContext(frame);
116-
return getOrCreateProc(declarationContext, symbol);
119+
final Map<RubyModule, RubyModule[]> refinements = getRefinements(frame);
120+
return getOrCreateProc(refinements, symbol);
117121
}
118122

119123
@TruffleBoundary
120-
protected RubyProc getOrCreateProc(DeclarationContext declarationContext, RubySymbol symbol) {
121-
declarationContext = declarationContext == null ? DeclarationContext.NONE : declarationContext;
124+
protected RubyProc getOrCreateProc(Map<RubyModule, RubyModule[]> refinements, RubySymbol symbol) {
125+
// TODO (eregon, 23 Sep 2020): this should ideally cache on the refinements by comparing classes, and not by identity.
122126
return ConcurrentOperations.getOrCompute(
123127
symbol.getCachedProcs(),
124-
declarationContext,
125-
key -> createProc(key, symbol));
128+
refinements,
129+
key -> createProc(getContext(), key, symbol));
126130
}
127131

128132
@TruffleBoundary
129-
protected RubyProc createProc(DeclarationContext declarationContext, RubySymbol symbol) {
130-
final InternalMethod method = getContext().getCoreMethods().SYMBOL_TO_PROC;
133+
protected static RubyProc createProc(RubyContext context, Map<RubyModule, RubyModule[]> refinements,
134+
RubySymbol symbol) {
135+
final InternalMethod method = context.getCoreMethods().SYMBOL_TO_PROC;
131136
final SourceSection sourceSection = CoreLibrary.UNAVAILABLE_SOURCE_SECTION;
137+
final DeclarationContext declarationContext = refinements.isEmpty()
138+
? DeclarationContext.NONE
139+
: new DeclarationContext(Visibility.PUBLIC, null, refinements);
140+
132141
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(
133142
sourceSection,
134143
method.getLexicalScope(),
@@ -145,9 +154,9 @@ protected RubyProc createProc(DeclarationContext declarationContext, RubySymbol
145154
// binding as this simplifies the logic elsewhere in the runtime.
146155
final MaterializedFrame declarationFrame = Truffle
147156
.getRuntime()
148-
.createMaterializedFrame(args, coreLibrary().emptyDescriptor);
157+
.createMaterializedFrame(args, context.getCoreLibrary().emptyDescriptor);
149158
final RubyRootNode rootNode = new RubyRootNode(
150-
getContext(),
159+
context,
151160
sourceSection,
152161
new FrameDescriptor(nil),
153162
sharedMethodInfo,
@@ -157,7 +166,7 @@ protected RubyProc createProc(DeclarationContext declarationContext, RubySymbol
157166
final RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode);
158167

159168
return ProcOperations.createRubyProc(
160-
getContext().getCoreLibrary().procShape,
169+
context.getCoreLibrary().procShape,
161170
ProcType.PROC,
162171
sharedMethodInfo,
163172
callTarget,
@@ -173,12 +182,16 @@ protected InternalMethod getMethod(VirtualFrame frame) {
173182
return RubyArguments.getMethod(frame);
174183
}
175184

176-
protected int getCacheLimit() {
177-
return getContext().getOptions().SYMBOL_TO_PROC_CACHE;
185+
protected Map<RubyModule, RubyModule[]> getRefinements(VirtualFrame frame) {
186+
final MaterializedFrame callerFrame = readCallerFrame.execute(frame);
187+
final DeclarationContext declarationContext = RubyArguments.tryGetDeclarationContext(callerFrame);
188+
return declarationContext != null
189+
? declarationContext.getRefinements()
190+
: DeclarationContext.NONE.getRefinements();
178191
}
179192

180-
protected DeclarationContext getDeclarationContext(VirtualFrame frame) {
181-
return RubyArguments.tryGetDeclarationContext(readCallerFrame.execute(frame));
193+
protected int getCacheLimit() {
194+
return getContext().getOptions().SYMBOL_TO_PROC_CACHE;
182195
}
183196

184197
}

0 commit comments

Comments
 (0)