|
20 | 20 | import org.truffleruby.builtins.PrimitiveArrayArgumentsNode;
|
21 | 21 | import org.truffleruby.core.basicobject.RubyBasicObject;
|
22 | 22 | import org.truffleruby.core.cast.BooleanCastWithDefaultNodeGen;
|
23 |
| -import org.truffleruby.core.kernel.TruffleKernelNodesFactory.SetFrameAndThreadLocalVariableFactory; |
| 23 | +import org.truffleruby.core.kernel.TruffleKernelNodesFactory.GetSpecialVariableStorageNodeGen; |
24 | 24 | import org.truffleruby.core.module.ModuleNodes;
|
25 | 25 | import org.truffleruby.core.module.RubyModule;
|
26 | 26 | import org.truffleruby.core.string.RubyString;
|
27 | 27 | import org.truffleruby.core.proc.RubyProc;
|
28 | 28 | import org.truffleruby.core.symbol.RubySymbol;
|
29 |
| -import org.truffleruby.core.binding.RubyBinding; |
| 29 | +import org.truffleruby.language.Nil; |
| 30 | +import org.truffleruby.language.RubyContextNode; |
30 | 31 | import org.truffleruby.language.RubyNode;
|
31 | 32 | import org.truffleruby.language.RubyRootNode;
|
| 33 | +import org.truffleruby.language.arguments.ReadCallerStorageNode; |
| 34 | +import org.truffleruby.language.arguments.RubyArguments; |
32 | 35 | import org.truffleruby.language.control.RaiseException;
|
33 | 36 | import org.truffleruby.language.dispatch.DispatchNode;
|
34 | 37 | import org.truffleruby.language.globals.ReadSimpleGlobalVariableNode;
|
35 | 38 | import org.truffleruby.language.globals.WriteSimpleGlobalVariableNode;
|
36 | 39 | import org.truffleruby.language.loader.CodeLoader;
|
37 | 40 | import org.truffleruby.language.loader.FileLoader;
|
38 | 41 | import org.truffleruby.language.methods.DeclarationContext;
|
39 |
| -import org.truffleruby.language.threadlocal.FindThreadAndFrameLocalStorageNode; |
40 |
| -import org.truffleruby.language.threadlocal.FindThreadAndFrameLocalStorageNodeGen; |
| 42 | +import org.truffleruby.language.threadlocal.SpecialVariableStorage; |
41 | 43 | import org.truffleruby.parser.ParserContext;
|
42 | 44 | import org.truffleruby.parser.RubySource;
|
43 | 45 |
|
| 46 | +import com.oracle.truffle.api.Assumption; |
| 47 | +import com.oracle.truffle.api.CompilerDirectives; |
44 | 48 | import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
45 | 49 | import com.oracle.truffle.api.dsl.Cached;
|
46 | 50 | import com.oracle.truffle.api.dsl.CreateCast;
|
47 | 51 | import com.oracle.truffle.api.dsl.ImportStatic;
|
48 | 52 | import com.oracle.truffle.api.dsl.NodeChild;
|
49 | 53 | import com.oracle.truffle.api.dsl.Specialization;
|
| 54 | +import com.oracle.truffle.api.frame.FrameDescriptor; |
| 55 | +import com.oracle.truffle.api.frame.FrameSlot; |
| 56 | +import com.oracle.truffle.api.frame.FrameSlotKind; |
| 57 | +import com.oracle.truffle.api.frame.FrameUtil; |
| 58 | +import com.oracle.truffle.api.frame.MaterializedFrame; |
| 59 | +import com.oracle.truffle.api.frame.VirtualFrame; |
50 | 60 | import com.oracle.truffle.api.nodes.IndirectCallNode;
|
51 | 61 | import com.oracle.truffle.api.profiles.ConditionProfile;
|
52 | 62 |
|
@@ -172,37 +182,181 @@ protected Object defineHookedVariableInnerNode(
|
172 | 182 |
|
173 | 183 | }
|
174 | 184 |
|
175 |
| - @Primitive(name = "frame_local_variable_get") |
176 |
| - public abstract static class GetFrameAndThreadLocalVariable extends PrimitiveArrayArgumentsNode { |
| 185 | + @ImportStatic(Layouts.class) |
| 186 | + public abstract static class GetSpecialVariableStorage extends RubyContextNode { |
| 187 | + |
| 188 | + public abstract SpecialVariableStorage execute(VirtualFrame frame); |
| 189 | + |
| 190 | + @Specialization( |
| 191 | + guards = "frame.getFrameDescriptor() == descriptor", |
| 192 | + assumptions = "frameAssumption", |
| 193 | + limit = "1") |
| 194 | + protected SpecialVariableStorage getFromKnownFrameDescriptor(VirtualFrame frame, |
| 195 | + @Cached("frame.getFrameDescriptor()") FrameDescriptor descriptor, |
| 196 | + @Cached("declarationDepth(frame)") int declarationFrameDepth, |
| 197 | + @Cached("declarationDescriptor(frame, declarationFrameDepth)") FrameDescriptor declarationFrameDescriptor, |
| 198 | + @Cached("declarationSlot(declarationFrameDescriptor)") FrameSlot declarationFrameSlot, |
| 199 | + @Cached("declarationFrameDescriptor.getVersion()") Assumption frameAssumption) { |
| 200 | + Object storage; |
| 201 | + if (declarationFrameDepth == 0) { |
| 202 | + storage = FrameUtil.getObjectSafe(frame, declarationFrameSlot); |
| 203 | + if (storage == nil) { |
| 204 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 205 | + storage = new SpecialVariableStorage(); |
| 206 | + frame.setObject(declarationFrameSlot, storage); |
| 207 | + } |
| 208 | + } else { |
| 209 | + MaterializedFrame storageFrame = RubyArguments.getDeclarationFrame(frame, declarationFrameDepth); |
| 210 | + |
| 211 | + storage = FrameUtil.getObjectSafe(storageFrame, declarationFrameSlot); |
| 212 | + if (storage == nil) { |
| 213 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 214 | + storage = new SpecialVariableStorage(); |
| 215 | + storageFrame.setObject(declarationFrameSlot, storage); |
| 216 | + } |
| 217 | + } |
| 218 | + return (SpecialVariableStorage) storage; |
| 219 | + } |
177 | 220 |
|
178 |
| - @Child FindThreadAndFrameLocalStorageNode threadLocalNode = FindThreadAndFrameLocalStorageNodeGen.create(); |
| 221 | + @Specialization(replaces = "getFromKnownFrameDescriptor") |
| 222 | + protected SpecialVariableStorage slowPath(VirtualFrame frame) { |
| 223 | + return getSlow(frame.materialize()); |
| 224 | + } |
179 | 225 |
|
180 |
| - @Specialization |
181 |
| - protected Object executeGetValue(RubySymbol name, RubyBinding binding, |
182 |
| - @Cached ConditionProfile sameThreadProfile) { |
183 |
| - return threadLocalNode.execute(name, binding.getFrame()).get(sameThreadProfile); |
| 226 | + @TruffleBoundary |
| 227 | + public static SpecialVariableStorage getSlow(MaterializedFrame aFrame) { |
| 228 | + MaterializedFrame frame = aFrame; |
| 229 | + |
| 230 | + while (true) { |
| 231 | + final FrameSlot slot = getVariableSlot(frame); |
| 232 | + if (slot != null) { |
| 233 | + Object storage = FrameUtil.getObjectSafe(frame, slot); |
| 234 | + if (storage == Nil.INSTANCE) { |
| 235 | + storage = new SpecialVariableStorage(); |
| 236 | + frame.setObject(slot, storage); |
| 237 | + } |
| 238 | + return (SpecialVariableStorage) storage; |
| 239 | + } |
| 240 | + |
| 241 | + final MaterializedFrame nextFrame = RubyArguments.getDeclarationFrame(frame); |
| 242 | + if (nextFrame != null) { |
| 243 | + frame = nextFrame; |
| 244 | + } else { |
| 245 | + FrameSlot newSlot = frame |
| 246 | + .getFrameDescriptor() |
| 247 | + .findOrAddFrameSlot(Layouts.SPECIAL_VARIABLES_STORAGE); |
| 248 | + SpecialVariableStorage storage = new SpecialVariableStorage(); |
| 249 | + frame.setObject(newSlot, storage); |
| 250 | + return storage; |
| 251 | + } |
| 252 | + } |
| 253 | + } |
| 254 | + |
| 255 | + protected int declarationDepth(VirtualFrame topFrame) { |
| 256 | + MaterializedFrame frame = topFrame.materialize(); |
| 257 | + int count = 0; |
| 258 | + |
| 259 | + while (true) { |
| 260 | + final FrameSlot slot = getVariableSlot(frame); |
| 261 | + if (slot != null) { |
| 262 | + return count; |
| 263 | + } |
| 264 | + |
| 265 | + final MaterializedFrame nextFrame = RubyArguments.getDeclarationFrame(frame); |
| 266 | + if (nextFrame != null) { |
| 267 | + frame = nextFrame; |
| 268 | + count++; |
| 269 | + } else { |
| 270 | + return count; |
| 271 | + } |
| 272 | + } |
184 | 273 | }
|
185 | 274 |
|
| 275 | + protected FrameDescriptor declarationDescriptor(VirtualFrame topFrame, int depth) { |
| 276 | + if (depth == 0) { |
| 277 | + return topFrame.getFrameDescriptor(); |
| 278 | + } else { |
| 279 | + return RubyArguments.getDeclarationFrame(topFrame, depth).getFrameDescriptor(); |
| 280 | + } |
| 281 | + } |
| 282 | + |
| 283 | + @TruffleBoundary |
| 284 | + protected FrameSlot declarationSlot(FrameDescriptor descriptor) { |
| 285 | + return descriptor.findOrAddFrameSlot(Layouts.SPECIAL_VARIABLES_STORAGE, FrameSlotKind.Object); |
| 286 | + } |
| 287 | + |
| 288 | + private static FrameSlot getVariableSlot(MaterializedFrame frame) { |
| 289 | + return frame.getFrameDescriptor().findFrameSlot(Layouts.SPECIAL_VARIABLES_STORAGE); |
| 290 | + } |
| 291 | + |
| 292 | + public static GetSpecialVariableStorage create() { |
| 293 | + return GetSpecialVariableStorageNodeGen.create(); |
| 294 | + } |
186 | 295 | }
|
187 | 296 |
|
188 |
| - @Primitive(name = "frame_local_variable_set") |
189 |
| - public abstract static class SetFrameAndThreadLocalVariable extends PrimitiveArrayArgumentsNode { |
| 297 | + @Primitive(name = "caller_special_variables") |
| 298 | + public abstract static class GetCallerSpecialVariableStorage extends PrimitiveArrayArgumentsNode { |
190 | 299 |
|
191 |
| - @Child FindThreadAndFrameLocalStorageNode threadLocalNode = FindThreadAndFrameLocalStorageNodeGen.create(); |
| 300 | + @Child ReadCallerStorageNode callerStorageNode = new ReadCallerStorageNode(); |
192 | 301 |
|
193 |
| - public static SetFrameAndThreadLocalVariable create() { |
194 |
| - return SetFrameAndThreadLocalVariableFactory.create(null); |
| 302 | + @Specialization |
| 303 | + protected Object storage(VirtualFrame frame) { |
| 304 | + return callerStorageNode.execute(frame); |
195 | 305 | }
|
| 306 | + } |
| 307 | + |
| 308 | + @Primitive(name = "proc_special_variables") |
| 309 | + public abstract static class GetProcSpecialVariableStorage extends PrimitiveArrayArgumentsNode { |
| 310 | + |
| 311 | + @Specialization |
| 312 | + protected Object storage(VirtualFrame frame, RubyProc proc) { |
| 313 | + return proc.declarationStorage; |
| 314 | + } |
| 315 | + } |
| 316 | + |
| 317 | + @Primitive(name = "regexp_last_match_set") |
| 318 | + public abstract static class SetRegexpMatch extends PrimitiveArrayArgumentsNode { |
| 319 | + |
| 320 | + @Specialization |
| 321 | + protected Object executeSetRegexpMatch(SpecialVariableStorage storage, Object lastMatch, |
| 322 | + @Cached ConditionProfile unsetProfile, |
| 323 | + @Cached ConditionProfile sameThreadProfile) { |
| 324 | + storage.setLastMatch(lastMatch, getContext(), unsetProfile, sameThreadProfile); |
| 325 | + return lastMatch; |
| 326 | + } |
| 327 | + } |
196 | 328 |
|
197 |
| - public abstract Object execute(RubySymbol name, Object value, RubyBinding binding); |
| 329 | + @Primitive(name = "regexp_last_match_get") |
| 330 | + public abstract static class GetRegexpMatch extends PrimitiveArrayArgumentsNode { |
198 | 331 |
|
199 | 332 | @Specialization
|
200 |
| - protected Object set(RubySymbol name, Object value, RubyBinding binding, |
| 333 | + protected Object executeSetRegexpMatch(SpecialVariableStorage storage, |
| 334 | + @Cached ConditionProfile unsetProfile, |
201 | 335 | @Cached ConditionProfile sameThreadProfile) {
|
202 |
| - threadLocalNode.execute(name, binding.getFrame()).set(value, sameThreadProfile); |
203 |
| - return value; |
| 336 | + return storage.getLastMatch(unsetProfile, sameThreadProfile); |
204 | 337 | }
|
| 338 | + } |
| 339 | + |
| 340 | + @Primitive(name = "io_last_line_set") |
| 341 | + public abstract static class SetLastIO extends PrimitiveArrayArgumentsNode { |
205 | 342 |
|
| 343 | + @Specialization |
| 344 | + protected Object executeSetRegexpMatch(SpecialVariableStorage storage, Object lastIO, |
| 345 | + @Cached ConditionProfile unsetProfile, |
| 346 | + @Cached ConditionProfile sameThreadProfile) { |
| 347 | + storage.setLastLine(lastIO, getContext(), unsetProfile, sameThreadProfile); |
| 348 | + return lastIO; |
| 349 | + } |
206 | 350 | }
|
207 | 351 |
|
| 352 | + @Primitive(name = "io_last_line_get") |
| 353 | + public abstract static class GetLastIO extends PrimitiveArrayArgumentsNode { |
| 354 | + |
| 355 | + @Specialization |
| 356 | + protected Object executeSetRegexpMatch(SpecialVariableStorage storage, |
| 357 | + @Cached ConditionProfile unsetProfile, |
| 358 | + @Cached ConditionProfile sameThreadProfile) { |
| 359 | + return storage.getLastLine(unsetProfile, sameThreadProfile); |
| 360 | + } |
| 361 | + } |
208 | 362 | }
|
0 commit comments