9
9
*/
10
10
package org .truffleruby .core .symbol ;
11
11
12
+ import org .graalvm .collections .Pair ;
12
13
import org .truffleruby .RubyContext ;
13
14
import org .truffleruby .RubyLanguage ;
14
15
import org .truffleruby .builtins .CoreMethod ;
25
26
import org .truffleruby .core .proc .RubyProc ;
26
27
import org .truffleruby .core .string .RubyString ;
27
28
import org .truffleruby .core .string .StringNodes ;
29
+ import org .truffleruby .language .LexicalScope ;
28
30
import org .truffleruby .language .RubyRootNode ;
29
31
import org .truffleruby .language .Visibility ;
30
32
import org .truffleruby .language .arguments .ReadCallerFrameNode ;
@@ -122,74 +124,56 @@ public static ToProcNode create() {
122
124
protected RubyProc toProcCached (VirtualFrame frame , RubySymbol symbol ,
123
125
@ Cached ("symbol" ) RubySymbol cachedSymbol ,
124
126
@ Cached ("getRefinements(frame)" ) Map <RubyModule , RubyModule []> cachedRefinements ,
125
- @ Cached ("getOrCreateProc(getContext(), getLanguage(), cachedRefinements, symbol)" ) RubyProc cachedProc ) {
127
+ @ Cached ("getOrCreateCallTarget(getContext(), getLanguage(), cachedSymbol, cachedRefinements)" ) RootCallTarget callTarget ,
128
+ @ Cached ("createProc(getContext(), getLanguage(), cachedRefinements, callTarget)" ) RubyProc cachedProc ) {
126
129
return cachedProc ;
127
130
}
128
131
129
132
@ Specialization (replaces = "toProcCached" )
130
133
protected RubyProc toProcUncached (VirtualFrame frame , RubySymbol symbol ) {
131
134
final Map <RubyModule , RubyModule []> refinements = getRefinements (frame );
132
- return getOrCreateProc (getContext (), getLanguage (), refinements , symbol );
135
+ final RootCallTarget callTarget = getOrCreateCallTarget (getContext (), getLanguage (), symbol , refinements );
136
+ return createProc (getContext (), getLanguage (), refinements , callTarget );
133
137
}
134
138
135
139
@ TruffleBoundary
136
- public static RubyProc getOrCreateProc (
137
- RubyContext context ,
138
- RubyLanguage language ,
139
- Map <RubyModule , RubyModule []> refinements ,
140
- RubySymbol symbol ) {
141
- // TODO (eregon, 23 Sep 2020): this should ideally cache on the refinements by comparing classes, and not by identity.
142
- return ConcurrentOperations .getOrCompute (
143
- symbol .getCachedProcs (),
144
- refinements ,
145
- key -> createProc (context , language , key , symbol ));
146
- }
147
-
148
- @ TruffleBoundary
149
- private static RubyProc createProc (RubyContext context , RubyLanguage language ,
150
- Map <RubyModule , RubyModule []> refinements ,
151
- RubySymbol symbol ) {
140
+ public static RootCallTarget getOrCreateCallTarget (RubyContext context , RubyLanguage language ,
141
+ RubySymbol symbol , Map <RubyModule , RubyModule []> refinements ) {
142
+ if (refinements == DeclarationContext .NO_REFINEMENTS ) {
143
+ return symbol .getCallTargetNoRefinements (language );
144
+ } else {
145
+ // TODO (eregon, 23 Sep 2020): this should ideally cache on the refinements by comparing classes, and not by identity.
146
+ return ConcurrentOperations .getOrCompute (
147
+ context .cachedSymbolToProcTargetsWithRefinements ,
148
+ Pair .create (symbol , refinements ),
149
+ key -> createCallTarget (language , symbol , refinements ));
150
+ }
151
+ }
152
+
153
+ public static RubyProc createProc (RubyContext context , RubyLanguage language ,
154
+ Map <RubyModule , RubyModule []> refinements , RootCallTarget callTarget ) {
152
155
final InternalMethod method = context .getCoreMethods ().SYMBOL_TO_PROC ;
153
- final SourceSection sourceSection = CoreLibrary .UNAVAILABLE_SOURCE_SECTION ;
154
- final DeclarationContext declarationContext = refinements .isEmpty ()
156
+ final DeclarationContext declarationContext = refinements == DeclarationContext .NO_REFINEMENTS
155
157
? DeclarationContext .NONE
156
158
: new DeclarationContext (Visibility .PUBLIC , null , refinements );
157
159
158
- final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo (
159
- sourceSection ,
160
- method .getLexicalScope (),
161
- ARITY ,
162
- null ,
163
- symbol .getString (),
164
- 0 ,
165
- "proc" ,
166
- ArgumentDescriptor .ANON_REST );
167
160
final Object [] args = RubyArguments
168
161
.pack (null , null , method , declarationContext , null , nil , null , EMPTY_ARGUMENTS );
169
- // MRI raises an error on Proc#binding if you attempt to access the binding of a procedure generated
162
+ // MRI raises an error on Proc#binding if you attempt to access the binding of a Proc generated
170
163
// by Symbol#to_proc. We generate a declaration frame here so that all procedures will have a
171
164
// binding as this simplifies the logic elsewhere in the runtime.
172
165
final MaterializedFrame declarationFrame = Truffle
173
166
.getRuntime ()
174
- .createMaterializedFrame (args , context .getCoreLibrary ().emptyDeclarationDescriptor );
167
+ .createVirtualFrame (args , context .getCoreLibrary ().emptyDeclarationDescriptor )
168
+ .materialize ();
175
169
SpecialVariableStorage variables = new SpecialVariableStorage ();
176
170
declarationFrame .setObject (context .getCoreLibrary ().emptyDeclarationSpecialVariableSlot , variables );
177
171
178
- final RubyRootNode rootNode = new RubyRootNode (
179
- language ,
180
- sourceSection ,
181
- new FrameDescriptor (nil ),
182
- sharedMethodInfo ,
183
- new SymbolProcNode (symbol .getString ()),
184
- Split .HEURISTIC );
185
-
186
- final RootCallTarget callTarget = Truffle .getRuntime ().createCallTarget (rootNode );
187
-
188
172
return ProcOperations .createRubyProc (
189
173
context .getCoreLibrary ().procClass ,
190
174
language .procShape ,
191
175
ProcType .PROC ,
192
- sharedMethodInfo ,
176
+ (( RubyRootNode ) callTarget . getRootNode ()). getSharedMethodInfo () ,
193
177
callTarget ,
194
178
callTarget ,
195
179
declarationFrame ,
@@ -200,6 +184,32 @@ private static RubyProc createProc(RubyContext context, RubyLanguage language,
200
184
declarationContext );
201
185
}
202
186
187
+ public static RootCallTarget createCallTarget (RubyLanguage language , RubySymbol symbol ,
188
+ // unused but the CallTarget will capture the refinements in the DispatchNode on first call
189
+ Map <RubyModule , RubyModule []> refinements ) {
190
+ final SourceSection sourceSection = CoreLibrary .UNAVAILABLE_SOURCE_SECTION ;
191
+
192
+ final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo (
193
+ sourceSection ,
194
+ LexicalScope .IGNORE ,
195
+ ARITY ,
196
+ null ,
197
+ symbol .getString (),
198
+ 0 ,
199
+ "proc" ,
200
+ ArgumentDescriptor .ANON_REST );
201
+
202
+ final RubyRootNode rootNode = new RubyRootNode (
203
+ language ,
204
+ sourceSection ,
205
+ new FrameDescriptor (nil ),
206
+ sharedMethodInfo ,
207
+ new SymbolProcNode (symbol .getString ()),
208
+ Split .HEURISTIC );
209
+
210
+ return Truffle .getRuntime ().createCallTarget (rootNode );
211
+ }
212
+
203
213
protected InternalMethod getMethod (VirtualFrame frame ) {
204
214
return RubyArguments .getMethod (frame );
205
215
}
0 commit comments