|
57 | 57 | import com.oracle.truffle.api.frame.MaterializedFrame;
|
58 | 58 | import com.oracle.truffle.api.frame.VirtualFrame;
|
59 | 59 | import com.oracle.truffle.api.source.SourceSection;
|
| 60 | +import org.truffleruby.language.locals.WriteFrameSlotNode; |
| 61 | +import org.truffleruby.language.locals.WriteFrameSlotNodeGen; |
60 | 62 | import org.truffleruby.parser.ParentFrameDescriptor;
|
61 | 63 | import org.truffleruby.parser.TranslatorEnvironment;
|
62 | 64 |
|
@@ -309,6 +311,34 @@ public RubyNode cloneUninitialized() {
|
309 | 311 | }
|
310 | 312 | }
|
311 | 313 |
|
| 314 | + @GenerateUncached |
| 315 | + @ImportStatic(BindingNodes.class) |
| 316 | + public abstract static class LocalVariableGetNode extends RubyBaseNode { |
| 317 | + |
| 318 | + public abstract Object execute(RubyBinding binding, String name); |
| 319 | + |
| 320 | + @Specialization(guards = "!isHiddenVariable(name)") |
| 321 | + protected Object localVariableGet(RubyBinding binding, String name, |
| 322 | + @Cached FindDeclarationVariableNodes.FindAndReadDeclarationVariableNode readNode) { |
| 323 | + MaterializedFrame frame = binding.getFrame(); |
| 324 | + Object result = readNode.execute(frame, name, null); |
| 325 | + if (result == null) { |
| 326 | + throw new RaiseException( |
| 327 | + getContext(), |
| 328 | + coreExceptions().nameErrorLocalVariableNotDefined(name, binding, this)); |
| 329 | + } |
| 330 | + return result; |
| 331 | + } |
| 332 | + |
| 333 | + @TruffleBoundary |
| 334 | + @Specialization(guards = "isHiddenVariable(name)") |
| 335 | + protected Object localVariableGetLastLine(RubyBinding binding, String name) { |
| 336 | + throw new RaiseException( |
| 337 | + getContext(), |
| 338 | + coreExceptions().nameError("Bad local variable name", binding, name, this)); |
| 339 | + } |
| 340 | + } |
| 341 | + |
312 | 342 | @ReportPolymorphism
|
313 | 343 | @GenerateNodeFactory
|
314 | 344 | @CoreMethod(names = "local_variable_set", required = 2)
|
@@ -347,6 +377,88 @@ public RubyNode cloneUninitialized() {
|
347 | 377 | }
|
348 | 378 | }
|
349 | 379 |
|
| 380 | + |
| 381 | + @GenerateUncached |
| 382 | + @ImportStatic({ BindingNodes.class, FindDeclarationVariableNodes.class }) |
| 383 | + public abstract static class LocalVariableSetNode extends RubyBaseNode { |
| 384 | + |
| 385 | + public abstract Object execute(RubyBinding binding, String name, Object value); |
| 386 | + |
| 387 | + @Specialization( |
| 388 | + guards = { |
| 389 | + "name == cachedName", |
| 390 | + "!isHiddenVariable(cachedName)", |
| 391 | + "getFrameDescriptor(binding) == cachedFrameDescriptor", |
| 392 | + "cachedFrameSlot != null" }, |
| 393 | + limit = "getCacheLimit()") |
| 394 | + protected Object localVariableSetCached(RubyBinding binding, String name, Object value, |
| 395 | + @Cached("name") String cachedName, |
| 396 | + @Cached("getFrameDescriptor(binding)") FrameDescriptor cachedFrameDescriptor, |
| 397 | + @Cached("findFrameSlotOrNull(name, binding.getFrame())") FindDeclarationVariableNodes.FrameSlotAndDepth cachedFrameSlot, |
| 398 | + @Cached("createWriteNode(cachedFrameSlot.slot)") WriteFrameSlotNode writeLocalVariableNode) { |
| 399 | + final MaterializedFrame frame = RubyArguments |
| 400 | + .getDeclarationFrame(binding.getFrame(), cachedFrameSlot.depth); |
| 401 | + writeLocalVariableNode.executeWrite(frame, value); |
| 402 | + return value; |
| 403 | + } |
| 404 | + |
| 405 | + @Specialization( |
| 406 | + guards = { |
| 407 | + "name == cachedName", |
| 408 | + "!isHiddenVariable(cachedName)", |
| 409 | + "getFrameDescriptor(binding) == cachedFrameDescriptor", |
| 410 | + "cachedFrameSlot == null" }, |
| 411 | + limit = "getCacheLimit()") |
| 412 | + protected Object localVariableSetNewCached(RubyBinding binding, String name, Object value, |
| 413 | + @Cached("name") String cachedName, |
| 414 | + @Cached("getFrameDescriptor(binding)") FrameDescriptor cachedFrameDescriptor, |
| 415 | + @Cached("findFrameSlotOrNull(name, binding.getFrame())") FindDeclarationVariableNodes.FrameSlotAndDepth cachedFrameSlot, |
| 416 | + @Cached("newFrameDescriptor(cachedFrameDescriptor, name)") FrameDescriptor newDescriptor, |
| 417 | + @Cached("createWriteNode(NEW_VAR_INDEX)") WriteFrameSlotNode writeLocalVariableNode) { |
| 418 | + final MaterializedFrame frame = newFrame(binding, newDescriptor); |
| 419 | + writeLocalVariableNode.executeWrite(frame, value); |
| 420 | + return value; |
| 421 | + } |
| 422 | + |
| 423 | + @TruffleBoundary |
| 424 | + @Specialization( |
| 425 | + guards = "!isHiddenVariable(name)", |
| 426 | + replaces = { "localVariableSetCached", "localVariableSetNewCached" }) |
| 427 | + protected Object localVariableSetUncached(RubyBinding binding, String name, Object value) { |
| 428 | + MaterializedFrame frame = binding.getFrame(); |
| 429 | + final FindDeclarationVariableNodes.FrameSlotAndDepth frameSlot = FindDeclarationVariableNodes |
| 430 | + .findFrameSlotOrNull(name, frame); |
| 431 | + final int slot; |
| 432 | + if (frameSlot != null) { |
| 433 | + frame = RubyArguments.getDeclarationFrame(frame, frameSlot.depth); |
| 434 | + slot = frameSlot.slot; |
| 435 | + } else { |
| 436 | + var newDescriptor = newFrameDescriptor(getFrameDescriptor(binding), name); |
| 437 | + frame = newFrame(binding, newDescriptor); |
| 438 | + assert newDescriptor.getSlotName(NEW_VAR_INDEX) == name; |
| 439 | + slot = NEW_VAR_INDEX; |
| 440 | + } |
| 441 | + frame.setObject(slot, value); |
| 442 | + return value; |
| 443 | + } |
| 444 | + |
| 445 | + @TruffleBoundary |
| 446 | + @Specialization(guards = "isHiddenVariable(name)") |
| 447 | + protected Object localVariableSetLastLine(RubyBinding binding, String name, Object value) { |
| 448 | + throw new RaiseException( |
| 449 | + getContext(), |
| 450 | + coreExceptions().nameError("Bad local variable name", binding, name, this)); |
| 451 | + } |
| 452 | + |
| 453 | + protected WriteFrameSlotNode createWriteNode(int frameSlot) { |
| 454 | + return WriteFrameSlotNodeGen.create(frameSlot); |
| 455 | + } |
| 456 | + |
| 457 | + protected int getCacheLimit() { |
| 458 | + return getLanguage().options.BINDING_LOCAL_VARIABLE_CACHE; |
| 459 | + } |
| 460 | + } |
| 461 | + |
350 | 462 | @Primitive(name = "local_variable_names")
|
351 | 463 | @ImportStatic(BindingNodes.class)
|
352 | 464 | public abstract static class LocalVariablesNode extends PrimitiveArrayArgumentsNode {
|
|
0 commit comments