diff options
author | Alan Wu <[email protected]> | 2019-07-13 12:04:01 -0400 |
---|---|---|
committer | Alan Wu <[email protected]> | 2019-12-21 09:08:52 -0500 |
commit | 85a337f986fe6da99c7f8358f790f17b122b3903 (patch) | |
tree | f5c41137c2db802327cd4c405de7a922cbae7453 /vm_core.h | |
parent | ddb6023d64a8c96348b4e67603753e2916a04f28 (diff) |
Kernel#lambda: return forwarded block as non-lambda proc
Before this commit, Kernel#lambda can't tell the difference between a
directly passed literal block and one passed with an ampersand.
A block passed with an ampersand is semantically speaking already a
non-lambda proc. When Kernel#lambda receives a non-lambda proc, it
should simply return it.
Implementation wise, when the VM calls a method with a literal block, it
places the code for the block on the calling control frame and passes a
pointer (block handler) to the callee. Before this commit, the VM
forwards block arguments by simply forwarding the block handler, which
leaves the slot for block code unused when a control frame forwards its
block argument. I use the vacant space to indicate that a frame has
forwarded its block argument and inspect that in Kernel#lambda to detect
forwarded blocks.
This is a very ad-hoc solution and relies *heavily* on the way block
passing works in the VM. However, it's the most self-contained solution
I have.
[Bug #15620]
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/2289
Diffstat (limited to 'vm_core.h')
-rw-r--r-- | vm_core.h | 8 |
1 files changed, 7 insertions, 1 deletions
@@ -763,7 +763,7 @@ typedef struct rb_control_frame_struct { const rb_iseq_t *iseq; /* cfp[2] */ VALUE self; /* cfp[3] / block[0] */ const VALUE *ep; /* cfp[4] / block[1] */ - const void *block_code; /* cfp[5] / block[2] */ /* iseq or ifunc */ + const void *block_code; /* cfp[5] / block[2] */ /* iseq or ifunc or forwarded block handler */ VALUE *__bp__; /* cfp[6] */ /* outside vm_push_frame, use vm_base_ptr instead. */ #if VM_DEBUG_BP_CHECK @@ -1494,6 +1494,12 @@ vm_block_handler_verify(MAYBE_UNUSED(VALUE block_handler)) (vm_block_handler_type(block_handler), 1)); } +static inline int +vm_cfp_forwarded_bh_p(const rb_control_frame_t *cfp, VALUE block_handler) +{ + return ((VALUE) cfp->block_code) == block_handler; +} + static inline enum rb_block_type vm_block_type(const struct rb_block *block) { |