Bug #20916
openPrism compiler should support ** in Ractor constant
Description
The Prism compiler raises an exception against the following code.
$ ./miniruby -e '# shareable_constant_value: experimental_everything
C = { **{ } }'
-e:2: Ractor constant writes do not support **
-e: node type not implemented (NotImplementedError)
But the traditional compiler support it, and @ko1 (Koichi Sasada) said it should be supported.
Also, I feel that this error message node type not implemented
is a sign of a worse problem. Actually, valgrind reports Conditional jump or move depends on uninitialised value(s)
against the Prism compiler. An assertion failure is also reported.
$ valgrind ./miniruby -e '# shareable_constant_value: experimental_everything
C = { **{ } }'
==49978== Memcheck, a memory error detector
==49978== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==49978== Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
==49978== Command: ./miniruby -e #\ shareable_constant_value:\ experimental_everything_C\ =\ {\ **{\ }\ }
==49978==
==49978== Warning: set address range perms: large range [0x64e0000, 0x1e4e0000) (defined)
-e:2: Ractor constant writes do not support **
==49978== Conditional jump or move depends on uninitialised value(s)
==49978== at 0x4BB42A: pm_newline_list_line (pm_newline_list.c:63)
==49978== by 0x1E718A: pm_compile_shareable_constant_value (prism_compile.c:5280)
==49978== by 0x1E7243: pm_compile_shareable_constant_value (prism_compile.c:5318)
==49978== by 0x1E8DC1: pm_compile_constant_write_node.isra.0 (prism_compile.c:5372)
==49978== by 0x1DCB2F: pm_compile_node (prism_compile.c:9823)
==49978== by 0x1DC9C8: pm_compile_node (prism_compile.c:9934)
==49978== by 0x1F3AC9: pm_compile_scope_node.isra.0 (prism_compile.c:6603)
==49978== by 0x1DA66A: pm_compile_node (prism_compile.c:9805)
==49978== by 0x1F61A7: pm_iseq_compile_node (prism_compile.c:10109)
==49978== by 0x2A5303: pm_iseq_new_with_opt_try (iseq.c:1027)
==49978== by 0x23DFF2: rb_protect (eval.c:1033)
==49978== by 0x2AB198: pm_iseq_new_with_opt (iseq.c:1080)
==49978==
miniruby: prism/util/pm_newline_list.c:63: pm_newline_list_line: Assertion `cursor >= list->start' failed.
==49978==
==49978== Process terminating with default action of signal 6 (SIGABRT)
==49978== at 0x4AFAB1C: __pthread_kill_implementation (pthread_kill.c:44)
==49978== by 0x4AFAB1C: __pthread_kill_internal (pthread_kill.c:78)
==49978== by 0x4AFAB1C: pthread_kill@@GLIBC_2.34 (pthread_kill.c:89)
==49978== by 0x4AA126D: raise (raise.c:26)
==49978== by 0x4A848FE: abort (abort.c:79)
==49978== by 0x4A8481A: __assert_fail_base.cold (assert.c:94)
==49978== by 0x4A97506: __assert_fail (assert.c:103)
==49978== by 0x4BB49B: pm_newline_list_line (pm_newline_list.c:63)
==49978== by 0x1E718A: pm_compile_shareable_constant_value (prism_compile.c:5280)
==49978== by 0x1E7243: pm_compile_shareable_constant_value (prism_compile.c:5318)
==49978== by 0x1E8DC1: pm_compile_constant_write_node.isra.0 (prism_compile.c:5372)
==49978== by 0x1DCB2F: pm_compile_node (prism_compile.c:9823)
==49978== by 0x1DC9C8: pm_compile_node (prism_compile.c:9934)
==49978== by 0x1F3AC9: pm_compile_scope_node.isra.0 (prism_compile.c:6603)
==49978==
==49978== HEAP SUMMARY:
==49978== in use at exit: 2,645,494 bytes in 10,084 blocks
==49978== total heap usage: 36,662 allocs, 26,578 frees, 6,066,537 bytes allocated
==49978==
==49978== LEAK SUMMARY:
==49978== definitely lost: 0 bytes in 0 blocks
==49978== indirectly lost: 0 bytes in 0 blocks
==49978== possibly lost: 1,050,576 bytes in 4 blocks
==49978== still reachable: 1,594,918 bytes in 10,080 blocks
==49978== suppressed: 0 bytes in 0 blocks
==49978== Rerun with --leak-check=full to see details of leaked memory
==49978==
==49978== Use --track-origins=yes to see where uninitialised values come from
==49978== For lists of detected and suppressed errors, rerun with: -s
==49978== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Aborted (core dumped)
Updated by kddnewton (Kevin Newton) 2 days ago
I'm fine supporting this, but I'm not sure what the behavior should be since the current compiler just segfaults. What is the behavior if the value being splatted isn't an empty hash?
Updated by tenderlovemaking (Aaron Patterson) 2 days ago
I created a bug for the parse.y version here: https://bugs.ruby-lang.org/issues/20926
The example @mame (Yusuke Endoh) provides works on Ruby 3.3. I think it's supposed to emit instructions like this:
$ ruby -v --dump=insns test.rb
ruby 3.3.4 (2024-07-16 revision 425e468d25) [arm64-darwin23]
== disasm: #<ISeq:<main>@test.rb:1 (1,0)-(3,13)>
0000 putobject {nil=>{}} ( 3)[Li]
0002 dup
0003 putspecialobject 3
0005 setconstant :C
0007 leave
Note that if you remove the comment the iseqs look like this:
$ ruby -v --dump=insns test.rb
ruby 3.3.4 (2024-07-16 revision 425e468d25) [arm64-darwin23]
== disasm: #<ISeq:<main>@test.rb:1 (1,0)-(2,13)>
0000 newhash 0 ( 2)[Li]
0002 dup
0003 putspecialobject 3
0005 setconstant :C
0007 leave
I think the main difference is the putobject
instruction.
Updated by tenderlovemaking (Aaron Patterson) 2 days ago
After reading the instruction sequences, I realized that Ruby 3.3 has an odd behavior with shareable_constant_value: experimental_everything
. I filed an issue about it here: https://bugs.ruby-lang.org/issues/20927
I personally think the fix for this ticket is that C
should be an empty hash (whether the comment is there or not).
Updated by tenderlovemaking (Aaron Patterson) 2 days ago
- Related to Bug #20927: `{ **{ } }` behaves differently when `shareable_constant_value: experimental_everything` added
Updated by hsbt (Hiroshi SHIBATA) 2 days ago
- Status changed from Open to Assigned