Ruby Issue Tracking System: Issueshttps://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112024-03-22T01:58:03ZRuby Issue Tracking System
Redmine Ruby master - Misc #20387 (Open): Meta-ticket for ASAN supporthttps://bugs.ruby-lang.org/issues/203872024-03-22T01:58:03Zkjtsanaktsidis (KJ Tsanaktsidis)kjtsanaktsidis@gmail.com
<p>I was asked to provide a bit of information about the current status of ASAN in CRuby, so I thought I'd open this meta-ticket to track all of the work I've been performing on fixing up address sanitizer support.</p>
<p>So far, I have fixed the following issues related to ASAN support:</p>
<ul>
<li>
<a href="https://bugs.ruby-lang.org/issues/20001" class="external">https://bugs.ruby-lang.org/issues/20001</a> + <a href="https://github.com/ruby/ruby/pull/9505" class="external">https://github.com/ruby/ruby/pull/9505</a>, which dealt with two main themes:
<ul>
<li>Pushing the logic for capturing the start of the machine stack much closer to the top of the call stack, so that VALUEs stored close to the top of the machine stack get marked properly</li>
<li>Marking VALUEs stored on ASAN fake stacks during machine stack marking</li>
</ul>
</li>
<li>
<a href="https://bugs.ruby-lang.org/issues/20220" class="external">https://bugs.ruby-lang.org/issues/20220</a> + <a href="https://github.com/ruby/ruby/pull/9734" class="external">https://github.com/ruby/ruby/pull/9734</a>, which made M:N threading notify ASAN about stack switches in the same way that fibers do
<ul>
<li>Note: ASAN still doesn't work with M:N threading, but that actually has nothing to do with ASAN; it's because the most recent versions of Clang which are needed for ASAN just don't work with M:N threading either. See <a href="https://bugs.ruby-lang.org/issues/20243" class="external">https://bugs.ruby-lang.org/issues/20243</a> for more info about that.</li>
</ul>
</li>
<li>
<a href="https://bugs.ruby-lang.org/issues/20273" class="external">https://bugs.ruby-lang.org/issues/20273</a> + <a href="https://github.com/ruby/ruby/pull/10012" class="external">https://github.com/ruby/ruby/pull/10012</a>, which disables <code>callcc</code> (and the associated tests) when ASAN is enabled
<ul>
<li>callcc is very rarely used in real code and the way it works is just fundamentally incompatible with ASAN (it performs longjmp's which I think are technically undefined behaviour)</li>
</ul>
</li>
<li>
<a href="https://bugs.ruby-lang.org/issues/20221" class="external">https://bugs.ruby-lang.org/issues/20221</a> + <a href="https://github.com/ruby/ruby/pull/9865" class="external">https://github.com/ruby/ruby/pull/9865</a>, which ignore some global symbols that ASAN defines from the global symbol leak checker</li>
<li>
<a href="https://bugs.ruby-lang.org/issues/20274" class="external">https://bugs.ruby-lang.org/issues/20274</a> + <a href="https://github.com/ruby/ruby/pull/10087" class="external">https://github.com/ruby/ruby/pull/10087</a>, which ignores some false positive tests about memory leaks when ASAN is enabl</li>
<li>I updated the ASAN docs in <a href="https://github.com/ruby/ruby/pull/9922" class="external">https://github.com/ruby/ruby/pull/9922</a> to more closely reflect current reality</li>
</ul>
<p>The current state of things is that, by following the instructions in <a href="https://github.com/ruby/ruby/blob/master/doc/contributing/building_ruby.md" class="external">https://github.com/ruby/ruby/blob/master/doc/contributing/building_ruby.md</a>, you can successfully build Ruby with ASAN enabled, however, the test suite has several failures. I'm currently working on addressing these:</p>
<p>The next step is to merge <a href="https://github.com/ruby/ruby/pull/10122" class="external">https://github.com/ruby/ruby/pull/10122</a> (<a href="https://bugs.ruby-lang.org/issues/20310" class="external">https://bugs.ruby-lang.org/issues/20310</a>) which I plan to do next week (I'm currently away on a work trip). That makes sure that VALUEs stored in ASAN fake stacks from threads other than the currently running thread get marked during GC.</p>
<p>After that, I need to push up patches for the remaining few issues. I mostly have these patches ready to go already; in fact, last week I got the full <code>make check</code> suite passing all tests with ASAN enabled!</p>
<p>Once that's working, I'd like to investigate how ASAN can fit into CRuby's CI matrix somewhere so that it <em>stays</em> working, although I have not thought too deeply about this yet.</p>
<p>I will provide further updates on this ticket so anybody interested can stay in the loop.</p> Ruby master - Feature #20261 (Open): Add symbol synonyms for '' and nil for IO method line separa...https://bugs.ruby-lang.org/issues/202612024-02-12T20:34:51Zburdettelamar (Burdette Lamar)
<p>[Feature 20261] For IO's line-oriented read methods, there are two special values for the line-separator argument <code>sep</code>; I'm proposing to add (user-friendlier) symbol synonyms for those values:</p>
<ul>
<li>
<code>:paragraph</code> as synonym for <code>''</code> (read paragraphs).</li>
<li>
<code>:slurp</code> as synonym for <code>nil</code> (read all).</li>
</ul>
<p>Details (code, documentation, tests) may be seen at <a href="https://github.com/ruby/ruby/pull/9921" class="external">https://github.com/ruby/ruby/pull/9921</a>.</p> Ruby master - Bug #20255 (Open): Embedded arrays aren't moved correctly across ractorshttps://bugs.ruby-lang.org/issues/202552024-02-10T17:31:30Zluke-gru (Luke Gruber)luke.gru@gmail.com
<p><code>ractor.send(ary, move: true)</code> works incorrectly because if <code>ary</code> is embedded, the new moved object doesn't populate its own embedded space, it uses the MovedObject's embedded space.</p>
<p>example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">r</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span>
<span class="n">inner_ary</span> <span class="o">=</span> <span class="n">receive</span>
<span class="n">values</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">values</span><span class="p">[</span><span class="ss">:equal</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">inner_ary</span> <span class="o">==</span> <span class="p">[</span><span class="s2">""</span><span class="p">,{},</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">])</span>
<span class="n">values</span><span class="p">[</span><span class="ss">:string</span><span class="p">]</span> <span class="o">=</span> <span class="n">inner_ary</span><span class="p">.</span><span class="nf">to_s</span>
<span class="n">values</span>
<span class="p">}</span>
<span class="n">ary</span> <span class="o">=</span> <span class="p">[</span><span class="no">String</span><span class="p">.</span><span class="nf">new</span><span class="p">,</span><span class="no">Hash</span><span class="p">.</span><span class="nf">new</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">]</span>
<span class="n">r</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">ary</span><span class="p">,</span> <span class="ss">move: </span><span class="kp">true</span><span class="p">)</span>
<span class="n">r_values</span> <span class="o">=</span> <span class="n">r</span><span class="p">.</span><span class="nf">take</span>
<span class="nb">p</span> <span class="n">r_values</span><span class="p">[</span><span class="ss">:equal</span><span class="p">]</span>
<span class="nb">p</span> <span class="n">r_values</span><span class="p">[</span><span class="ss">:string</span><span class="p">]</span>
<span class="c1"># => false</span>
<span class="c1"># => "[\"\", {}, 2, 2.0, 21747991570, String, 3]"</span>
</code></pre> Ruby master - Bug #20225 (Open): Inconsistent behavior of regex matching for a regex has a null loophttps://bugs.ruby-lang.org/issues/202252024-01-30T02:53:03Zmake_now_just (Hiroya Fujinami)make.just.on@gmail.com
<p>Usually, in Ruby (Onigmo), when a null loop (a loop consuming no characters) occurs on regex matching, this loop is terminated. But, if a loop has a capture and some complex condition is satisfied, this causes backtracking. This behavior invokes unexpected results, for example,</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">p</span> <span class="sr">/(?:.B.(?<a>(?:[C-Z]|.)*)+){2}/</span> <span class="o">=~</span> <span class="s2">"ABCABC"</span> <span class="c1"># => nil</span>
<span class="nb">p</span> <span class="sr">/(?:.B.(?:(?:[C-Z]|.)*)+){2}/</span> <span class="o">=~</span> <span class="s2">"ABCABC"</span> <span class="c1"># => 0</span>
</code></pre>
<p>Because the above regex has a capture and the below does not, different matching results are returned. It is not very intuitive that the presence of a capture changes the matching result.</p>
<p>The detailed condition for changing the null-loop behavior is 1) a previous capture in this loop holds the empty string, and 2) this capture's position is different from the current matching position. This condition is checked in <code>STACK_NULL_CHECK_MEMST</code> (<a href="https://github.com/ruby/ruby/blob/bbb7ab906ec64b963bd4b5d37e47b14796d64371/regexec.c#L1766-L1778" class="external">https://github.com/ruby/ruby/blob/bbb7ab906ec64b963bd4b5d37e47b14796d64371/regexec.c#L1766-L1778</a>).</p>
<p>Perhaps, you cannot understand what this condition means. Don't worry, I also cannot understand. This condition has been introduced for at least 20 years, and no one may remember the reason for this necessity. (If you know, please tell me!) Even if there is a reason, I believe that there is no reasonable authority for allowing counter-intuitive behavior, such as the above example.</p>
<p>This behavior can also cause memoization to be buggy. Memoization relies on the fact that backtracking only depends on positions and states (byte-code offsets of a regex). However, this condition additionally refers to captures, and the memoization is broken.</p>
<p>My proposal is to <strong>correct this inconsistent behavior</strong>. Specifically, a null loop should be determined solely on the basis of whether the matching position has changed, without referring to captures.</p>
<p>This fix changes the behavior of regex matching, but I believe that the probability that this will actually cause backward compatibility problems is remarkably low. This is because I have never seen any mention of this puzzling behavior before.</p> Ruby master - Feature #20105 (Open): Introduce `IO::Stream` or something similar.https://bugs.ruby-lang.org/issues/201052024-01-01T07:43:50Zioquatix (Samuel Williams)samuel@oriontransfer.net
<p>Ruby's IO class has a general model for streaming IO, including some hidden classes like <code>IO::generic_readable</code> and <code>IO::generic_writable</code>.</p>
<p>As Ruby's core IO classes evolve, gems like <code>openssl</code> (see <code>OpenSSL::Buffering</code>) need to be updated to support changes to the interface.</p>
<p>As it stands, there are changes in <code>IO</code> which are not copied to <code>OpenSSL::Buffering</code>. I'd like to propose we introduce some shared interface for streams that is used by <code>IO</code>, <code>Socket</code>, and <code>OpenSSL</code> to start with. The general interface would be similar to <code>IO</code> and allow code like <code>OpenSSL</code> to avoid re-implementing the <code>IO</code> interface.</p>
<p>I don't have a strong idea for the interface yet, but it would probably look something like this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">IO::Stream</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">io</span><span class="p">,</span> <span class="ss">buffered: </span><span class="kp">true</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">read</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="n">buffer</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">write</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="n">buffer</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1"># Include general operations from IO, like gets, puts, etc</span>
<span class="k">end</span>
</code></pre>
<p>I think ideally we'd try implement with pure Ruby and a first goal would be to replace <code>OpenSSL::Buffering</code>.</p> Ruby master - Feature #20102 (Open): Introduce `Fiber#resuming?`https://bugs.ruby-lang.org/issues/201022023-12-28T07:25:59Zioquatix (Samuel Williams)samuel@oriontransfer.net
<p>There are some tricky edge cases when using <code>Fibre#raise</code> and <code>Fiber#kill</code>, e.g.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">fiber</span> <span class="o">=</span> <span class="kp">nil</span>
<span class="n">killer</span> <span class="o">=</span> <span class="no">Fiber</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="n">fiber</span><span class="p">.</span><span class="nf">raise</span><span class="p">(</span><span class="s2">"Stop"</span><span class="p">)</span>
<span class="k">end</span>
<span class="n">fiber</span> <span class="o">=</span> <span class="no">Fiber</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="n">killer</span><span class="p">.</span><span class="nf">resume</span>
<span class="k">end</span>
<span class="n">fiber</span><span class="p">.</span><span class="nf">resume</span>
<span class="c1"># 4:in `raise': attempt to raise a resuming fiber (FiberError)</span>
<span class="c1"># 4:in `block in <main>'</span>
</code></pre>
<p>Async has to deal with this edge case explicitly by rescuing the exception:</p>
<p><a href="https://github.com/socketry/async/blob/ffd019d9c1d547926a28fe8f36bf7bfe91d8a168/lib/async/task.rb#L226-L233" class="external">https://github.com/socketry/async/blob/ffd019d9c1d547926a28fe8f36bf7bfe91d8a168/lib/async/task.rb#L226-L233</a></p>
<p>I'd like to avoid doing that and instead just ask "Can I kill/raise on this fiber right now?" which is determined by whether the fiber itself can be resumed or transferred to.</p>
<p>To address this, I'd like to introduce <code>Fiber#resuming?</code>:</p>
<pre><code class="c syntaxhl" data-language="c"><span class="cm">/*
* call-seq: fiber.resumed? -> true or false
*
* Whether the fiber is currently resumed.
*/</span>
<span class="n">VALUE</span>
<span class="nf">rb_fiber_resuming_p</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">fiber_value</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">struct</span> <span class="n">rb_fiber_struct</span> <span class="o">*</span><span class="n">fiber</span> <span class="o">=</span> <span class="n">fiber_ptr</span><span class="p">(</span><span class="n">fiber_value</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">FIBER_TERMINATED_P</span><span class="p">(</span><span class="n">fiber</span><span class="p">))</span> <span class="k">return</span> <span class="n">RUBY_Qfalse</span><span class="p">;</span>
<span class="k">return</span> <span class="n">RBOOL</span><span class="p">(</span><span class="n">fiber</span><span class="o">-></span><span class="n">resuming_fiber</span><span class="p">);</span>
<span class="p">}</span>
</code></pre>
<p>See the PR: <a href="https://github.com/ruby/ruby/pull/9382" class="external">https://github.com/ruby/ruby/pull/9382</a></p> Ruby master - Bug #20082 (Open): Killing fibers across threads: unexpected exceptionhttps://bugs.ruby-lang.org/issues/200822023-12-23T21:15:27Zzverok (Victor Shepelev)zverok.offline@gmail.com
<p>For providing the example in a changelog, I tried to imitate killing fibers belonging to other threads.<br>
Documentation <a href="https://docs.ruby-lang.org/en/master/Fiber.html#method-i-kill" class="external">claims</a></p>
<blockquote>
<p>Raises FiberError if called on a fiber belonging to another thread.</p>
</blockquote>
<p>So, I created this artificial example to check how it works:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">fibers</span> <span class="o">=</span> <span class="p">[]</span>
<span class="no">Thread</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span>
<span class="n">f</span> <span class="o">=</span> <span class="no">Fiber</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="p">).</span><span class="nf">each</span> <span class="p">{</span> <span class="nb">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> <span class="p">}</span> <span class="p">}</span>
<span class="n">fibers</span> <span class="o"><<</span> <span class="n">f</span>
<span class="n">f</span><span class="p">.</span><span class="nf">resume</span>
<span class="p">}</span>
<span class="nb">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> <span class="c1"># to make sure the thread has started</span>
<span class="n">fibers</span><span class="p">.</span><span class="nf">last</span><span class="p">.</span><span class="nf">kill</span>
</code></pre>
<p>The example indeed fails with <code>FiberError</code>, but the error message is confusing:</p>
<pre><code>in `kill': attempt to resume a resumed fiber (double resume) (FiberError)
</code></pre>
<p>Is this an expected message for such case? Or am I misunderstanding something?</p> Ruby master - Feature #19840 (Open): [Proposal] Expand Find pattern to Multiple Findhttps://bugs.ruby-lang.org/issues/198402023-08-18T04:28:57ZFlickGradley (Nick Bradley)
<p>Hello! I love Ruby's pattern matching features. I would like to propose an expansion of the Find pattern which allows the selection of multiple matching elements of an array.</p>
<p>I often find myself dealing with data like this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">{</span> <span class="ss">results: </span><span class="p">[{</span> <span class="ss">id: </span><span class="mi">1</span><span class="p">,</span> <span class="ss">name: </span><span class="s2">"foo"</span> <span class="p">},</span> <span class="p">{</span> <span class="ss">id: </span><span class="mi">2</span><span class="p">,</span> <span class="ss">name: </span><span class="s2">"bar"</span> <span class="p">},</span> <span class="o">...</span> <span class="p">]</span> <span class="p">}</span>
</code></pre>
<p>My problem is that I need to retrieve all the <code>id</code> values from the nested array of hashes, and I don't know how many there will be in advance.</p>
<p>It seems that the Find pattern could be expanded from allowing <code>pattern</code> (matching a single element) to <code>*pattern</code>. Examples:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># Base case</span>
<span class="k">case</span> <span class="p">{</span> <span class="ss">results: </span><span class="p">[{</span> <span class="ss">id: </span><span class="mi">1</span><span class="p">,</span> <span class="ss">name: </span><span class="s2">"foo"</span> <span class="p">},</span> <span class="p">{</span> <span class="ss">id: </span><span class="mi">2</span><span class="p">,</span> <span class="ss">name: </span><span class="s2">"bar"</span> <span class="p">}]</span> <span class="p">}</span>
<span class="k">in</span> <span class="ss">results: </span><span class="p">[</span><span class="o">*</span><span class="p">{</span> <span class="ss">id: </span><span class="n">ids</span> <span class="p">}]</span>
<span class="s2">"matched: </span><span class="si">#{</span><span class="n">ids</span><span class="si">}</span><span class="s2">"</span>
<span class="k">else</span>
<span class="s2">"not matched"</span>
<span class="k">end</span>
<span class="c1">#=> matched: [1, 2]</span>
<span class="c1"># With * at the end (rest of args) - same result</span>
<span class="k">case</span> <span class="p">{</span> <span class="ss">results: </span><span class="p">[{</span> <span class="ss">id: </span><span class="mi">1</span><span class="p">,</span> <span class="ss">name: </span><span class="s2">"foo"</span> <span class="p">},</span> <span class="p">{</span> <span class="ss">id: </span><span class="mi">2</span><span class="p">,</span> <span class="ss">name: </span><span class="s2">"bar"</span> <span class="p">}]</span> <span class="p">}</span>
<span class="k">in</span> <span class="ss">results: </span><span class="p">[</span><span class="o">*</span><span class="p">{</span> <span class="ss">id: </span><span class="n">ids</span> <span class="p">},</span> <span class="o">*</span><span class="p">]</span>
<span class="s2">"matched: </span><span class="si">#{</span><span class="n">ids</span><span class="si">}</span><span class="s2">"</span>
<span class="k">else</span>
<span class="s2">"not matched"</span>
<span class="k">end</span>
<span class="c1">#=> matched: [1, 2]</span>
<span class="c1"># When one element doesn't match and there is no *rest</span>
<span class="k">case</span> <span class="p">{</span> <span class="ss">results: </span><span class="p">[{</span> <span class="ss">name: </span><span class="s2">"foo"</span> <span class="p">},</span> <span class="p">{</span> <span class="ss">id: </span><span class="mi">2</span><span class="p">,</span> <span class="ss">name: </span><span class="s2">"bar"</span> <span class="p">}]</span> <span class="p">}</span>
<span class="k">in</span> <span class="ss">results: </span><span class="p">[</span><span class="o">*</span><span class="p">{</span> <span class="ss">id: </span><span class="n">ids</span> <span class="p">}]</span>
<span class="s2">"matched: </span><span class="si">#{</span><span class="n">ids</span><span class="si">}</span><span class="s2">"</span>
<span class="k">else</span>
<span class="s2">"not matched"</span>
<span class="k">end</span>
<span class="c1">#=> not matched</span>
</code></pre>
<p>Similarly, <code>*Constant</code> could work to pull out types with an As pattern:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">case</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="s2">"string"</span><span class="p">]</span>
<span class="k">in</span> <span class="o">*</span><span class="no">Integer</span> <span class="o">=></span> <span class="n">nums</span><span class="p">,</span> <span class="o">*</span>
<span class="s2">"matched: </span><span class="si">#{</span><span class="n">nums</span><span class="si">}</span><span class="s2">"</span>
<span class="k">else</span>
<span class="s2">"not matched"</span>
<span class="k">end</span>
<span class="c1">#=> matched: [1, 2, 3]</span>
</code></pre>
<p>Other patterns would work in the same way. Essentially, this expands the concept of <code>*</code> in pattern matching to mean "a variable number of <code>things matching subpattern</code>". Today, the only pattern supported by <code>*</code> is a variable binding - but it could be any of the other subpatterns as well.</p>
<p>This proposal does imply that this would work:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">a</span> <span class="o">=</span> <span class="mi">2</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span> <span class="k">in</span> <span class="p">[</span><span class="o">*</span><span class="p">,</span> <span class="o">*^</span><span class="n">a</span><span class="p">,</span> <span class="o">*</span><span class="p">]</span>
<span class="c1">#=> true</span>
</code></pre>
<p>To me, the <code>*</code> represents the variable number of matches, so the syntax makes intuitive sense. But others may have different opinions about <code>*^</code> being adjacent.</p>
<p>It may also imply this would work, though we could restrict the number of non-variable patterns (in other words, patterns that have the possibility of not matching) to 1 per Array so that this isn't possible.. I'm not sure something like this would be useful or clear.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">a</span> <span class="o">=</span> <span class="mi">2</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="s2">"hello"</span><span class="p">,</span> <span class="s2">"ruby"</span><span class="p">]</span> <span class="k">in</span> <span class="p">[</span><span class="o">*</span><span class="no">Integer</span><span class="p">,</span> <span class="o">*</span><span class="no">String</span><span class="p">]</span>
<span class="c1">#=> true</span>
</code></pre>
<p>This feature feels like the missing piece of the Find pattern to me - I often want to "Find Multiple". If others agree, I would be happy to contribute by working on this feature and creating a pull request.</p> Ruby master - Bug #19765 (Open): Ractor.make_shareable ignores self of a proc created from a Methodhttps://bugs.ruby-lang.org/issues/197652023-07-13T03:05:31ZEthan (Ethan -)notethan@gmail.com
<p>An unshareable receiver of a Proc or a Method will cause make_shareable to error, but this does not happen with a proc from Method#to_proc:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">str</span> <span class="o">=</span> <span class="s2">""</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">str</span><span class="p">.</span><span class="nf">instance_exec</span> <span class="p">{</span> <span class="nb">proc</span> <span class="p">{</span> <span class="nb">to_s</span> <span class="p">}</span> <span class="p">}</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">make_shareable</span> <span class="n">a</span>
<span class="c1"># => <internal:ractor>:820:in `make_shareable': Proc's self is not shareable: #<Proc:0x00000001064b62c8 (irb):1> (Ractor::IsolationError)</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">str</span><span class="p">.</span><span class="nf">instance_exec</span> <span class="p">{</span> <span class="nb">method</span><span class="p">(</span><span class="ss">:to_s</span><span class="p">)</span> <span class="p">}</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">make_shareable</span> <span class="n">b</span>
<span class="c1"># => <internal:ractor>:820:in `make_shareable': can not make shareable object for #<Method: String#to_s()> (Ractor::Error)</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">str</span><span class="p">.</span><span class="nf">instance_exec</span> <span class="p">{</span> <span class="nb">method</span><span class="p">(</span><span class="ss">:to_s</span><span class="p">).</span><span class="nf">to_proc</span> <span class="p">}</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">make_shareable</span> <span class="n">c</span>
<span class="n">c</span><span class="p">.</span><span class="nf">call</span>
<span class="c1"># => ""</span>
<span class="n">str</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"!"</span>
<span class="n">c</span><span class="p">.</span><span class="nf">call</span>
<span class="c1"># => "!"</span>
</code></pre>
<p>Related, maybe:<br>
<a class="issue tracker-1 status-2 priority-4 priority-default" title="Bug: Proc objects are not traversed for shareable check during Ractor.make_shareable(prok) (Assigned)" href="https://bugs.ruby-lang.org/issues/19372">#19372</a><br>
<a class="issue tracker-1 status-2 priority-4 priority-default" title="Bug: Issue with Ractor.make_shareable with curried procs (Assigned)" href="https://bugs.ruby-lang.org/issues/19374">#19374</a></p>
<p>Tangential: why does Proc cause Ractor::IsolationError but Method causes Ractor::Error?</p> Ruby master - Bug #19696 (Open): YJIT panicked - branch stubs should never enlarge brancheshttps://bugs.ruby-lang.org/issues/196962023-05-25T21:19:56Zwildmaples (Maple Ong)
<a name="Description"></a>
<h3 >Description<a href="#Description" class="wiki-anchor">¶</a></h3>
<p>We found this error on Rails CI with YJIT enabled. I'm not quite sure how to reproduce it since the error was intermittent.</p>
<p>I'm posting here to see if it is helpful or if anyone else has encountered this.</p>
<pre><code>thread '<unnamed>' panicked at 'branch stubs should never enlarge branches (start_addr: 0x7fa19e55cb99, old_size: 5, new_size: 14)', ./yjit/src/core.rs:1858:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb:587: [BUG] YJIT panicked
ruby 3.2.2 (2023-03-30 revision e51014f9c0) +jemalloc +YJIT [x86_64-linux]
-- Control frame information -----------------------------------------------
c:0131 p:0008 s:0680 e:000679 METHOD /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_adapters/abstract_a
c:0130 p:0004 s:0676 e:000675 BLOCK /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_adapters/abstract/c
c:0129 p:0079 s:0673 e:000671 METHOD /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activesupport/lib/active_support/callbacks.rb:107
c:0128 p:0009 s:0663 e:000662 METHOD /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activesupport/lib/active_support/callbacks.rb:929
c:0127 p:0005 s:0658 e:000657 METHOD /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_adapters/abstract/c
c:0126 p:0013 s:0653 e:000652 METHOD /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_adapters/abstract/c
c:0125 p:0011 s:0648 e:000647 METHOD /var/www/components/rails-backports/lib/rails/backports/7.0/abstract_adapter_thread_local_by_default.rb:97
c:0124 p:0021 s:0642 e:000638 METHOD /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_adapters/abstract/c
c:0123 p:0172 s:0635 e:000634 METHOD /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_adapters/abstract/c
c:0122 p:0014 s:0625 e:000624 METHOD /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_handling.rb:313
c:0121 p:0003 s:0621 e:000620 METHOD /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_handling.rb:280
c:0120 p:0004 s:0617 e:000616 BLOCK /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/fixtures.rb:560
c:0119 p:0087 s:0614 E:000b90 METHOD /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/fixtures.rb:575
c:0118 p:0015 s:0601 e:000600 METHOD /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/test_fixtures.rb:275
c:0117 p:0104 s:0596 E:002188 METHOD /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/test_fixtures.rb:125
c:0116 p:0008 s:0591 e:000590 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/isolator-0.8.0/lib/isolator/railtie.rb:27
c:0115 p:0003 s:0586 e:000585 METHOD /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/test_fixtures.rb:10
c:0114 p:0009 s:0582 e:000581 METHOD /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activesupport/lib/active_support/current_attributes/test_help
c:0113 p:0009 s:0578 e:000577 METHOD /var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activesupport/lib/active_support/execution_context/test_helpe
c:0112 p:0003 s:0574 e:000573 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-rails-6.0.2/lib/rspec/rails/adapters.rb:74 [FINISH]
c:0111 p:---- s:0570 e:000569 CFUNC :instance_exec
c:0110 p:0013 s:0565 e:000564 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457
c:0109 p:0010 s:0559 e:000558 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390
c:0108 p:0009 s:0553 e:000552 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628
c:0107 p:0018 s:0550 e:000549 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352
c:0106 p:0004 s:0544 e:000543 BLOCK /var/www/packs/tax_predictions/spec/support/tax_predictions.rb:11
c:0105 p:0018 s:0541 e:000540 METHOD /var/www/packs/tax_predictions/app/services/tax_predictions/testing.rb:14
c:0104 p:0021 s:0536 e:000535 BLOCK /var/www/packs/tax_predictions/spec/support/tax_predictions.rb:10 [FINISH]
c:0103 p:---- s:0532 e:000531 CFUNC :instance_exec
c:0102 p:0013 s:0527 e:000526 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457
c:0101 p:0010 s:0521 e:000520 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390
c:0100 p:0009 s:0515 e:000514 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628
c:0099 p:0018 s:0512 e:000511 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352
c:0098 p:0005 s:0506 e:000505 BLOCK /var/www/spec/support/initializers/system_exit.rb:14 [FINISH]
c:0097 p:---- s:0502 e:000501 CFUNC :instance_exec
c:0096 p:0013 s:0497 e:000496 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457
c:0095 p:0010 s:0491 e:000490 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390
c:0094 p:0009 s:0485 e:000484 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628
c:0093 p:0018 s:0482 e:000481 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352
c:0092 p:0041 s:0476 e:000475 BLOCK /var/www/spec/support/initializers/sidekiq_batch_middleware.rb:17 [FINISH]
c:0091 p:---- s:0471 e:000470 CFUNC :instance_exec
c:0090 p:0013 s:0466 e:000465 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457
c:0089 p:0010 s:0460 e:000459 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390
c:0088 p:0009 s:0454 e:000453 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628
c:0087 p:0018 s:0451 e:000450 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352
c:0086 p:0004 s:0445 e:000444 BLOCK /var/www/spec/support/initializers/sidekiq.rb:38
c:0085 p:0018 s:0442 e:000441 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/sidekiq-6.5.8/lib/sidekiq/testing.rb:16
c:0084 p:0009 s:0436 e:000435 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/sidekiq-6.5.8/lib/sidekiq/testing.rb:30
c:0083 p:0010 s:0431 e:000430 BLOCK /var/www/spec/support/initializers/sidekiq.rb:38 [FINISH]
c:0082 p:---- s:0427 e:000426 CFUNC :instance_exec
c:0081 p:0013 s:0422 e:000421 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457
c:0080 p:0010 s:0416 e:000415 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390
c:0079 p:0009 s:0410 e:000409 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628
c:0078 p:0018 s:0407 e:000406 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352
c:0077 p:0025 s:0401 e:000400 BLOCK /var/www/spec/support/initializers/rake.rb:18 [FINISH]
c:0076 p:---- s:0397 e:000396 CFUNC :instance_exec
c:0075 p:0013 s:0392 e:000391 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457
c:0074 p:0010 s:0386 e:000385 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390
c:0073 p:0009 s:0380 e:000379 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628
c:0072 p:0018 s:0377 e:000376 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352 [FINISH]
c:0071 p:---- s:0371 e:000370 IFUNC
c:0070 p:0116 s:0368 E:002008 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/prosopite-1.3.1/lib/prosopite.rb:49
c:0069 p:0023 s:0363 e:000362 BLOCK /var/www/spec/support/initializers/prosopite.rb:36 [FINISH]
c:0068 p:---- s:0359 e:000358 CFUNC :instance_exec
c:0067 p:0013 s:0354 e:000353 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457
c:0066 p:0010 s:0348 e:000347 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390
c:0065 p:0009 s:0342 e:000341 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628
c:0064 p:0018 s:0339 e:000338 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352
c:0063 p:0023 s:0333 e:000332 BLOCK /var/www/spec/support/initializers/logged_examples.rb:8 [FINISH]
c:0062 p:---- s:0329 e:000328 CFUNC :instance_exec
c:0061 p:0013 s:0324 e:000323 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457
c:0060 p:0010 s:0318 e:000317 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390
c:0059 p:0009 s:0312 e:000311 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628
c:0058 p:0018 s:0309 e:000308 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352
c:0057 p:0116 s:0303 e:000302 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/knapsack_pro-3.11.0/lib/knapsack_pro/adapters/rspec_adapter.rb:72 [FINISH]
c:0056 p:---- s:0298 e:000297 CFUNC :instance_exec
c:0055 p:0013 s:0293 e:000292 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457
c:0054 p:0010 s:0287 e:000286 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390
c:0053 p:0009 s:0281 e:000280 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628
c:0052 p:0018 s:0278 e:000277 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352
c:0051 p:0032 s:0272 e:000271 BLOCK /var/www/spec/support/initializers/flake_quarantine.rb:131 [FINISH]
c:0050 p:---- s:0268 e:000267 CFUNC :instance_exec
c:0049 p:0013 s:0263 e:000262 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457
c:0048 p:0010 s:0257 e:000256 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390
c:0047 p:0009 s:0251 e:000250 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628
c:0046 p:0018 s:0248 e:000247 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352
c:0045 p:0020 s:0242 e:000241 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/singed-0.2.1/lib/singed/rspec.rb:8 [FINISH]
c:0044 p:---- s:0238 e:000237 CFUNC :instance_exec
c:0043 p:0013 s:0233 e:000232 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457
c:0042 p:0010 s:0227 e:000226 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390
c:0041 p:0009 s:0221 e:000220 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628
c:0040 p:0018 s:0218 e:000217 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352 [FINISH]
c:0039 p:---- s:0212 e:000211 IFUNC
c:0038 p:0007 s:0209 e:000208 METHOD /var/www/spec/support/lib/stream_interceptor.rb:38
c:0037 p:0007 s:0205 e:000204 BLOCK /var/www/spec/support/initializers/stream_interception.rb:10 [FINISH]
c:0036 p:---- s:0201 e:000200 CFUNC :instance_exec
c:0035 p:0013 s:0196 e:000195 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457
c:0034 p:0010 s:0190 e:000189 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390
c:0033 p:0009 s:0184 e:000183 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628
c:0032 p:0018 s:0181 e:000180 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352
c:0031 p:0037 s:0175 E:0002c8 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:629
c:0030 p:0104 s:0168 E:000248 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:486
c:0029 p:0018 s:0161 E:0026e8 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:468
c:0028 p:0019 s:0156 E:002178 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:511
c:0027 p:0076 s:0151 E:000188 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:259
c:0026 p:0036 s:0144 e:000143 METHOD /var/www/components/flake_quarantine/lib/flake_quarantine/rspec/example.rb:11
c:0025 p:0037 s:0139 e:000138 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:646 [FINISH]
c:0024 p:---- s:0133 e:000132 CFUNC :map
c:0023 p:0011 s:0129 e:000128 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:642
c:0022 p:0052 s:0124 e:000123 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:607
c:0021 p:0006 s:0115 e:000114 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:608 [FINISH]
c:0020 p:---- s:0111 e:000110 CFUNC :map
c:0019 p:0065 s:0107 e:000106 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:608
c:0018 p:0006 s:0098 e:000097 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:608 [FINISH]
c:0017 p:---- s:0094 e:000093 CFUNC :map
c:0016 p:0065 s:0090 e:000089 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:608
c:0015 p:0007 s:0081 e:000080 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/runner.rb:121 [FINISH]
c:0014 p:---- s:0077 e:000076 CFUNC :map
c:0013 p:0030 s:0073 e:000072 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/runner.rb:121
c:0012 p:0026 s:0070 e:000069 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/configuration.rb:2070
c:0011 p:0007 s:0066 e:000065 BLOCK /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/runner.rb:116
c:0010 p:0009 s:0062 e:000061 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/reporter.rb:74
c:0009 p:0019 s:0057 e:000056 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/runner.rb:115
c:0008 p:0035 s:0050 e:000049 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/runner.rb:89
c:0007 p:0201 s:0044 e:000043 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/knapsack_pro-3.11.0/lib/knapsack_pro/runners/queue/rspec_runner.rb:93
c:0006 p:0161 s:0027 e:000026 METHOD /var/www/vendor/bundle/ruby/3.2.0/gems/knapsack_pro-3.11.0/lib/knapsack_pro/runners/queue/rspec_runner.rb:40
c:0005 p:0041 s:0019 E:000928 METHOD bin/rspec_runner:60
c:0004 p:0016 s:0014 e:000013 METHOD bin/rspec_runner:43
c:0003 p:0005 s:0010 e:000009 METHOD bin/rspec_runner:18
c:0002 p:0060 s:0006 e:000005 EVAL bin/rspec_runner:166 [FINISH]
c:0001 p:0000 s:0003 E:000c50 DUMMY [FINISH]
-- Ruby level backtrace information ----------------------------------------
bin/rspec_runner:166:in `<main>'
bin/rspec_runner:18:in `run'
bin/rspec_runner:43:in `run'
bin/rspec_runner:60:in `run_with_knapsack_pro'
/var/www/vendor/bundle/ruby/3.2.0/gems/knapsack_pro-3.11.0/lib/knapsack_pro/runners/queue/rspec_runner.rb:40:in `run'
/var/www/vendor/bundle/ruby/3.2.0/gems/knapsack_pro-3.11.0/lib/knapsack_pro/runners/queue/rspec_runner.rb:93:in `run_tests'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/runner.rb:89:in `run'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/runner.rb:115:in `run_specs'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/reporter.rb:74:in `report'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/runner.rb:116:in `block in run_specs'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/configuration.rb:2070:in `with_suite_hooks'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/runner.rb:121:in `block (2 levels) in run_specs'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/runner.rb:121:in `map'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/runner.rb:121:in `block (3 levels) in run_specs'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:608:in `run'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:608:in `map'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:608:in `block in run'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:608:in `run'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:608:in `map'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:608:in `block in run'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:607:in `run'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:642:in `run_examples'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:642:in `map'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example_group.rb:646:in `block in run_examples'
/var/www/components/flake_quarantine/lib/flake_quarantine/rspec/example.rb:11:in `run'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:259:in `run'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:511:in `with_around_and_singleton_context_hooks'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:468:in `with_around_example_hooks'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:486:in `run'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:629:in `run_around_example_hooks_for'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352:in `call'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390:in `execute_with'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/spec/support/initializers/stream_interception.rb:10:in `block (2 levels) in <top (required)>'
/var/www/spec/support/lib/stream_interceptor.rb:38:in `intercept'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352:in `call'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390:in `execute_with'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/vendor/bundle/ruby/3.2.0/gems/singed-0.2.1/lib/singed/rspec.rb:8:in `block (2 levels) in <main>'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352:in `call'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390:in `execute_with'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/spec/support/initializers/flake_quarantine.rb:131:in `block (2 levels) in <main>'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352:in `call'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390:in `execute_with'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/vendor/bundle/ruby/3.2.0/gems/knapsack_pro-3.11.0/lib/knapsack_pro/adapters/rspec_adapter.rb:72:in `block (2 levels) in bind_time_tracker'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352:in `call'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390:in `execute_with'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/spec/support/initializers/logged_examples.rb:8:in `block (2 levels) in <main>'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352:in `call'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390:in `execute_with'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/spec/support/initializers/prosopite.rb:36:in `block (2 levels) in <main>'
/var/www/vendor/bundle/ruby/3.2.0/gems/prosopite-1.3.1/lib/prosopite.rb:49:in `scan'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352:in `call'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390:in `execute_with'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/spec/support/initializers/rake.rb:18:in `block (2 levels) in <main>'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352:in `call'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390:in `execute_with'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/spec/support/initializers/sidekiq.rb:38:in `block (2 levels) in <main>'
/var/www/vendor/bundle/ruby/3.2.0/gems/sidekiq-6.5.8/lib/sidekiq/testing.rb:30:in `fake!'
/var/www/vendor/bundle/ruby/3.2.0/gems/sidekiq-6.5.8/lib/sidekiq/testing.rb:16:in `__set_test_mode'
/var/www/spec/support/initializers/sidekiq.rb:38:in `block (3 levels) in <main>'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352:in `call'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390:in `execute_with'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/spec/support/initializers/sidekiq_batch_middleware.rb:17:in `block (2 levels) in <main>'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352:in `call'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390:in `execute_with'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/spec/support/initializers/system_exit.rb:14:in `block (2 levels) in <main>'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352:in `call'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390:in `execute_with'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/packs/tax_predictions/spec/support/tax_predictions.rb:10:in `block (2 levels) in <main>'
/var/www/packs/tax_predictions/app/services/tax_predictions/testing.rb:14:in `recompute_on_fetch!'
/var/www/packs/tax_predictions/spec/support/tax_predictions.rb:11:in `block (3 levels) in <main>'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:352:in `call'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/hooks.rb:390:in `execute_with'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-core-3.12.2/lib/rspec/core/example.rb:457:in `instance_exec'
/var/www/vendor/bundle/ruby/3.2.0/gems/rspec-rails-6.0.2/lib/rspec/rails/adapters.rb:74:in `block (2 levels) in <module:MinitestLifecycleAdapter>'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activesupport/lib/active_support/execution_context/test_helper.rb:6:in `before_setup'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activesupport/lib/active_support/current_attributes/test_helper.rb:6:in `before_setup'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/test_fixtures.rb:10:in `before_setup'
/var/www/vendor/bundle/ruby/3.2.0/gems/isolator-0.8.0/lib/isolator/railtie.rb:27:in `setup_fixtures'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/test_fixtures.rb:125:in `setup_fixtures'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/test_fixtures.rb:275:in `load_fixtures'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/fixtures.rb:575:in `create_fixtures'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/fixtures.rb:560:in `block in create_fixtures'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_handling.rb:280:in `connection'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_handling.rb:313:in `retrieve_connection'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_adapters/abstract/connection_handler.rb:211:in `retrieve_connection'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:181:in `connection'
/var/www/components/rails-backports/lib/rails/backports/7.0/abstract_adapter_thread_local_by_default.rb:97:in `checkout'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:341:in `checkout'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:704:in `checkout_and_verify'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activesupport/lib/active_support/callbacks.rb:929:in `_run_checkout_callbacks'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activesupport/lib/active_support/callbacks.rb:107:in `run_callbacks'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:705:in `block in checkout_and_verify'
/var/www/vendor/bundle/ruby/3.2.0/bundler/gems/rails-c15ee6e7b506/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb:587:in `verify!'
-- C level backtrace information -------------------------------------------
/usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/libruby.so.3.2(rb_vm_bugreport+0xb2b) [0x7fa19a87c18b]
/usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/libruby.so.3.2(rb_bug_without_die+0x77) [0x7fa19a675937]
/usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/libruby.so.3.2(rb_bug+0x9f) [0x7fa19a5d0cd2]
/usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/libruby.so.3.2(_ZN4yjit4yjit17rb_bug_panic_hook28_$u7b$$u7b$closure$u7d$$u7d$17hfc31c2f18ccadc75E.llvm.12746241947442316067+0x5a) [0x7fa19a8b8d7a]
/usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/libruby.so.3.2(_ZN3std9panicking20rust_panic_with_hook17h66309baf5235212fE+0x3d3) [0x7fa19a8c9d73]
/usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/libruby.so.3.2(_ZN3std9panicking19begin_panic_handler28_$u7b$$u7b$closure$u7d$$u7d$17h3a147548aa082356E+0xb7) [0x7fa19a8ecb17]
/usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/libruby.so.3.2(_ZN3std10sys_common9backtrace26__rust_end_short_backtrace17hcc62583c733bef84E+0x14) [0x7fa19a8ec824]
/usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/libruby.so.3.2(rust_begin_unwind+0x42) [0x7fa19a8c9772]
/usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/libruby.so.3.2(_ZN4core9panicking9panic_fmt17h8531284c14f462dcE+0x33) [0x7fa19a5d8823]
/usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/libruby.so.3.2(_ZN4yjit4core20branch_stub_hit_body17h45fd758b20fb7aa6E+0xa03) [0x7fa19a89add3]
/usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/libruby.so.3.2(_ZN4yjit5cruby12with_vm_lock17h09508b1ca41af130E+0x49) [0x7fa19a8936b9]
/usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/libruby.so.3.2(_ZN4yjit4core15branch_stub_hit17h5cf8bd0b5727e3b9E.llvm.7796580109460741199+0x71) [0x7fa19a89ea31]
[0x7fa19b08501f]
-- Other runtime information -----------------------------------------------
* Loaded script: bin/rspec_runner
* Loaded features:
0 enumerator.so
1 thread.rb
2 fiber.so
3 rational.so
4 complex.so
5 ruby2_keywords.rb
6 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/x86_64-linux/enc/encdb.so
7 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/x86_64-linux/enc/trans/transdb.so
8 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/x86_64-linux/rbconfig.rb
9 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/compatibility.rb
10 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/defaults.rb
11 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/deprecate.rb
12 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/errors.rb
13 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/unknown_command_spell_checker.rb
14 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/exceptions.rb
15 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/basic_specification.rb
16 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/stub_specification.rb
17 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/platform.rb
18 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/util/list.rb
19 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/version.rb
20 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/requirement.rb
21 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/specification.rb
22 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/util.rb
23 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/dependency.rb
24 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/core_ext/kernel_gem.rb
25 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/x86_64-linux/monitor.so
26 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/monitor.rb
27 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems.rb
28 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/rubygems/path_support.rb
29 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/error_highlight/version.rb
30 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/error_highlight/base.rb
31 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/error_highlight/formatter.rb
32 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/error_highlight/core_ext.rb
33 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/error_highlight.rb
34 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/did_you_mean/version.rb
35 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/did_you_mean/core_ext/name_error.rb
36 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/did_you_mean/levenshtein.rb
37 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/did_you_mean/jaro_winkler.rb
38 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/did_you_mean/spell_checker.rb
39 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb
40 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb
41 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/did_you_mean/spell_checkers/name_error_checkers.rb
42 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/did_you_mean/spell_checkers/method_name_checker.rb
43 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/did_you_mean/spell_checkers/key_error_checker.rb
44 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/did_you_mean/spell_checkers/null_checker.rb
45 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/did_you_mean/tree_spell_checker.rb
46 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/did_you_mean/spell_checkers/require_path_checker.rb
47 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/did_you_mean/spell_checkers/pattern_key_name_checker.rb
48 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/did_you_mean/formatter.rb
49 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/did_you_mean.rb
50 /usr/lib/fullstaq-ruby/versions/3.2.2-jemalloc/lib/ruby/3.2.0/syntax_suggest/core_ext.rb
</code></pre> Ruby master - Feature #19642 (Open): Remove vectored read/write from `io.c`.https://bugs.ruby-lang.org/issues/196422023-05-15T06:33:11Zioquatix (Samuel Williams)samuel@oriontransfer.net
<p><a href="https://github.com/socketry/async/issues/228#issuecomment-1546789910" class="external">https://github.com/socketry/async/issues/228#issuecomment-1546789910</a> is a comment from the kernel developer who tells us that <code>writev</code> is always worse than <code>write</code> system call.</p>
<p>A large amount of complexity in <code>io.c</code> comes from optional support from <code>writev</code>.</p>
<p>So, I'd like to remove support for <code>writev</code>.</p>
<p>I may try to measure the performance before/after. However it may not show much difference, except that the implementation in <code>io.c</code> can be much simpler.</p> Ruby master - Feature #19472 (Open): Ractor::Selector to wait multiple ractorshttps://bugs.ruby-lang.org/issues/194722023-03-02T06:45:25Zko1 (Koichi Sasada)
<p>This ticket propose <code>Ractor::Selector</code> API to wait multiple ractor events.</p>
<p>Now, if we want to wait for taking from r1, r2 and r3, we can use <code>Ractor.select()</code> like that.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">r</span><span class="p">,</span> <span class="n">v</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="n">r1</span><span class="p">,</span> <span class="n">r2</span><span class="p">,</span> <span class="n">r3</span><span class="p">)</span>
<span class="nb">p</span> <span class="s2">"taking an object </span><span class="si">#{</span><span class="n">v</span><span class="si">}</span><span class="s2"> from </span><span class="si">#{</span><span class="n">r</span><span class="si">}</span><span class="s2">"</span>
</code></pre>
<p>With proposed <code>Ractor::Selector</code> API, we can write the following:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">selector</span> <span class="o">=</span> <span class="no">Ractor</span><span class="o">::</span><span class="no">Selector</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">r1</span><span class="p">,</span> <span class="n">r2</span><span class="p">)</span> <span class="c1"># make a waiting set with r1 and r2</span>
<span class="n">selector</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="n">r3</span><span class="p">)</span> <span class="c1"># we can add r3 to the waiting set after that.</span>
<span class="n">selector</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="n">r4</span><span class="p">)</span>
<span class="n">selector</span><span class="p">.</span><span class="nf">remove</span><span class="p">(</span><span class="n">r4</span><span class="p">)</span> <span class="c1"># we can remove r4 from the waiting set.</span>
<span class="n">r</span><span class="p">,</span> <span class="n">v</span> <span class="o">=</span> <span class="n">selector</span><span class="p">.</span><span class="nf">wait</span>
<span class="nb">p</span> <span class="s2">"taking an object </span><span class="si">#{</span><span class="n">v</span><span class="si">}</span><span class="s2"> from </span><span class="si">#{</span><span class="n">r</span><span class="si">}</span><span class="s2">"</span>
</code></pre>
<ul>
<li>
<code>Ractor::Selector.new(*ractors)</code>: creates a selector.</li>
<li>
<code>Ractor::Selector#add(r)</code>: adds <code>r</code> to the waiting set.</li>
<li>
<code>Ractor::Selector#remove(r)</code>: removes <code>r</code> from the waiting set.</li>
<li>
<code>Ractor::Selector#clear</code>: remove all ractors from the waiting set.</li>
<li>
<code>Ractor::Selector#empty?</code>: returns if the waiting set is empty or not.</li>
<li>
<code>Ractor::Selector#wait</code>: waits for the ractor events from the waiting set.</li>
</ul>
<p><a href="https://github.com/ruby/ruby/blob/master/ractor.rb#L380" class="external">https://github.com/ruby/ruby/blob/master/ractor.rb#L380</a></p>
<p>The advantages comparing with <code>Ractor.select</code> are:</p>
<ul>
<li>(1) (API design) We can preset the waiting set before waiting. Providing unified way to manage a waiting set seems better.</li>
<li>(2) (Performance) It is lighter than passing an array object to the <code>Ractor.select(*rs)</code> if <code>rs</code> is bigger and bigger.</li>
</ul>
<p>For (2), it is important to supervise thousands of ractors.</p>
<p><code>Ractor::Selector#wait</code> also has additional features:</p>
<ul>
<li>
<code>wait(receive: true)</code> also waits receiving.
<ul>
<li>
<code>Ractor.select(*rs, Ractor.current)</code> does same, but I believe <code>receive: true</code> keyword is more direct to understand.</li>
</ul>
</li>
<li>
<code>wait(yield_value: obj, move: true/false)</code> also waits yielding.
<ul>
<li>Same as <code>Ractor.select(yield_value: obj, move: true/false)</code>
</li>
</ul>
</li>
<li>If a ractor <code>r</code> is closing, then <code>#wait</code> removes <code>r</code> automatically.</li>
<li>If there is no waiting ractors, it raises an exception (now <code>Ractor::Error</code> is raised but it should be a better exception class)</li>
</ul>
<p>With automatic removing, we can write the code to wait n tasks.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">rs</span> <span class="o">=</span> <span class="n">n</span><span class="p">.</span><span class="nf">times</span><span class="p">.</span><span class="nf">map</span><span class="p">{</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">{</span> <span class="n">do_task</span> <span class="p">}</span> <span class="p">}</span>
<span class="n">selector</span> <span class="o">=</span> <span class="no">Ractor</span><span class="o">::</span><span class="no">Selector</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="o">*</span><span class="n">rs</span><span class="p">)</span>
<span class="kp">loop</span> <span class="k">do</span>
<span class="n">r</span><span class="p">,</span> <span class="n">v</span> <span class="o">=</span> <span class="n">selector</span><span class="p">.</span><span class="nf">wait</span>
<span class="n">handle_answers</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
<span class="k">rescue</span> <span class="no">Ractor</span><span class="o">::</span><span class="no">Error</span>
<span class="nb">p</span> <span class="ss">:all_tasks_done</span>
<span class="k">end</span>
</code></pre>
<p>Without auto removing, we can write the following code.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">rs</span> <span class="o">=</span> <span class="n">n</span><span class="p">.</span><span class="nf">times</span><span class="p">.</span><span class="nf">map</span><span class="p">{</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">{</span> <span class="n">do_task</span> <span class="p">}</span> <span class="p">}</span>
<span class="n">selector</span> <span class="o">=</span> <span class="no">Ractor</span><span class="o">::</span><span class="no">Selector</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="o">*</span><span class="n">rs</span><span class="p">)</span>
<span class="kp">loop</span> <span class="k">do</span>
<span class="n">r</span><span class="p">,</span> <span class="n">v</span> <span class="o">=</span> <span class="n">selector</span><span class="p">.</span><span class="nf">wait</span>
<span class="n">handle_answers</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
<span class="k">rescue</span> <span class="no">Ractor</span><span class="o">::</span><span class="no">ClosedError</span> <span class="o">=></span> <span class="n">e</span>
<span class="n">selector</span><span class="p">.</span><span class="nf">remove</span> <span class="n">e</span><span class="p">.</span><span class="nf">ractor</span>
<span class="k">rescue</span> <span class="no">Ractor</span><span class="o">::</span><span class="no">Error</span>
<span class="nb">p</span> <span class="ss">:all_tasks_done</span>
<span class="k">end</span>
<span class="c1"># or on this case worker ractors only yield one value (at exit) so the following code works as well.</span>
<span class="kp">loop</span> <span class="k">do</span>
<span class="n">r</span><span class="p">,</span> <span class="n">v</span> <span class="o">=</span> <span class="n">selector</span><span class="p">.</span><span class="nf">wait</span>
<span class="n">handle_answers</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
<span class="n">selector</span><span class="p">.</span><span class="nf">remove</span> <span class="n">r</span>
<span class="k">rescue</span> <span class="no">Ractor</span><span class="o">::</span><span class="no">Error</span>
<span class="nb">p</span> <span class="ss">:all_tasks_done</span>
<span class="k">end</span>
</code></pre>
<p>I already merged it but I want to discuss about the spec.</p>
<p>Discussion:</p>
<ul>
<li>The name <code>Selector</code> is acceptable?</li>
<li>Auto-removing seems convenient but it can hide the behavior.
<ul>
<li>allow auto-removing</li>
<li>allow auto-removing as configurable option
<ul>
<li>per ractor or per selector</li>
<li>which is default?</li>
</ul>
</li>
<li>disallow auto-removing</li>
</ul>
</li>
<li>What happens on no taking ractors
<ul>
<li>raise an exception (which exception?)</li>
<li>return nil simply</li>
</ul>
</li>
</ul>
<p>maybe and more...</p> Ruby master - Bug #19387 (Open): Issue with ObjectSpace.each_objects not returning objects after ...https://bugs.ruby-lang.org/issues/193872023-01-27T19:27:19Zluke-gru (Luke Gruber)luke.gru@gmail.com
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">r</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="n">receive</span> <span class="c1"># block, the problem is not the termination of the ractor but the starting</span>
<span class="k">end</span>
<span class="no">ObjectSpace</span><span class="p">.</span><span class="nf">each_object</span><span class="p">(</span><span class="no">IO</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">io</span><span class="o">|</span>
<span class="nb">p</span> <span class="n">io</span> <span class="c1"># we get no objects</span>
<span class="p">}</span>
</code></pre> Ruby master - Bug #19363 (Open): Fix rb_transient_heap_mark: wrong header (T_STRUCT) segfaulthttps://bugs.ruby-lang.org/issues/193632023-01-21T18:53:10Zbkuhlmann (Brooke Kuhlmann)brooke@alchemists.io
<a name="Overview"></a>
<h2 >Overview<a href="#Overview" class="wiki-anchor">¶</a></h2>
<p>Hello. 👋 I'm hitting an issue where my build is constantly failing with a segfault. The following is a snippet taken from my local machine with YJIT enabled (see attachments for details):</p>
<pre><code>/Users/bkuhlmann/.cache/frum/versions/3.2.0/lib/ruby/gems/3.2.0/gems/puma-6.0.2/lib/puma/runner.rb: [BUG] rb_transient_heap_mark: wrong header, T_STRUCT (0x0000000109ea98a0)
ruby 3.2.0 (2022-12-25 revision a528908271) +YJIT [arm64-darwin22.2.0]
</code></pre>
<p>The closest issue I could find that might be related to this issue (but not sure) is this issue: <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Segfault in rb_transient_heap_mark when running Sequel's specs (Closed)" href="https://bugs.ruby-lang.org/issues/15358">#15358</a>.</p>
<a name="Steps-to-Recreate"></a>
<h2 >Steps to Recreate<a href="#Steps-to-Recreate" class="wiki-anchor">¶</a></h2>
<p>You should be able to quickly recreate this issue via these steps:</p>
<ul>
<li>Download/clone my <a href="https://github.com/bkuhlmann/hemo" class="external">Hemo</a> project.</li>
<li>Run the setup steps.</li>
<li>Run the test suite by running <code>bin/rspec</code>.</li>
</ul>
<p>If you need an example of the same segfault (but not on my macOS machine), you can see the same segfault via my <a href="https://app.circleci.com/pipelines/github/bkuhlmann/hemo/11/workflows/f19abf41-60bc-4e8e-9ba9-b964a67ece73/jobs/10" class="external">Circle CI Build</a>. My Circle CI build is using my <a href="https://www.alchemists.io/projects/docker-alpine-ruby" class="external">Docker Alpine Linux Ruby</a> image which might be of interest as well. This Docker image is also built with YJIT enabled.</p>
<p>Interestingly, is if you were to run the test suite with <code>bin/guard</code> instead of <code>bin/rspec</code> then the segfault doesn't occur.</p>
<a name="Environment"></a>
<h2 >Environment<a href="#Environment" class="wiki-anchor">¶</a></h2>
<pre><code>ruby 3.2.0 (2022-12-25 revision a528908271) +YJIT [arm64-darwin22.2.0]
1.43.0 (using Parser 3.2.0.0, rubocop-ast 1.24.1, running on ruby 3.2.0) [arm64-darwin22.2.0]
- rubocop-performance 1.15.2
- rubocop-rake 0.6.0
- rubocop-rspec 2.18.1
- rubocop-sequel 0.3.4
- rubocop-thread_safety 0.4.4
</code></pre> Ruby master - Feature #19324 (Open): Enumerator.product => Enumerable#producthttps://bugs.ruby-lang.org/issues/193242023-01-08T15:06:51Zzverok (Victor Shepelev)zverok.offline@gmail.com
<p>I know it might be too late after introducing a feature and releasing a version, but I find <code>Enumerator.product</code> quite confusing, and can't find any justification in <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Enumerator.product: Cartesian product of enumerables (Closed)" href="https://bugs.ruby-lang.org/issues/18685">#18685</a>.</p>
<p><strong>Problem 1: It is <code>Array#product</code> but <code>Enumerator.product</code></strong></p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">].</span><span class="nf">product</span><span class="p">([</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">])</span>
<span class="c1"># => [[1, 4], [1, 5], [2, 4], [2, 5]]</span>
<span class="c1"># Usually, when we add methods to Enumerable/Enumerator which</span>
<span class="c1"># already array had before, it is symmetric, say...</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="kp">nil</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">].</span><span class="nf">compact</span> <span class="c1">#=> [1, 2, 3]</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="kp">nil</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">].</span><span class="nf">lazy</span><span class="p">.</span><span class="nf">compact</span><span class="p">.</span><span class="nf">first</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="c1">#=> [1, 2]</span>
<span class="c1"># But not in this case:</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">].</span><span class="nf">lazy</span><span class="p">.</span><span class="nf">product</span><span class="p">([</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">]).</span><span class="nf">first</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="c1"># undefined method `product' for #<Enumerator::Lazy: [1, 2]> (NoMethodError)</span>
<span class="c1"># Because you "just" need to change it to:</span>
<span class="no">Enumerator</span><span class="p">.</span><span class="nf">product</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">].</span><span class="nf">lazy</span><span class="p">,</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">]).</span><span class="nf">first</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="c1"># => [[1, 4], [1, 5]]</span>
</code></pre>
<p>No other method was "promoted" from Array this way</p>
<p>And in general, I believe core methods tend to belong to the first object in the expression and not be free module methods, Elixir style.</p>
<p><strong>Problem 2: It is one letter different from <code>Enumerator.produce</code></strong></p>
<p>I understand I might be biased here (as a person who proposed <code>produce</code>), and that method is not as popular (yet?) as I hoped, but still, two methods that do completely different things and differ by one letter, both being somewhat vague verbs (so it is easy to confuse them unless you did a lot of math and "product" is firmly set for set product in your head).</p>
<p>I believe that EITHER of two problems would be concerning enough, but the combination of them seems to be a strong enough argument to make the change?.. (Maybe with graceful deprecation of module method in one next version, but, considering the Ruby 3.2 is just released, maybe vice versa, fix the problem in the next minor release?..)</p> Ruby master - Misc #19304 (Open): Kernel vs Object documentationhttps://bugs.ruby-lang.org/issues/193042023-01-03T14:00:26Zzverok (Victor Shepelev)zverok.offline@gmail.com
<p>The restating of the problems raised in <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Move public methods from Kernel to Object (Rejected)" href="https://bugs.ruby-lang.org/issues/19300">#19300</a>, from scratch.</p>
<p>I believe it is rather a topic of <strong>community significance</strong> and would be happy if it is possible to <strong>discuss on dev-meeting</strong>, even if the outcome would probably "let's change RDoc in this or that way".</p>
<p>So, the problem statement:</p>
<ol>
<li>
<code>Kernel</code> module defines two "types" of methods: private ones, that pretend to be global (like <code>puts</code>), but actually available from inside every object; and public ones (like <code>#class</code> or <code>#frozen?</code>) that are present in every object including <code>Kernel</code>.</li>
<li>Since the beginning of times, docs provided an illusion that the second type of the methods belongs to <code>Object</code> class, which is, in fact, devoid of its own definitions, just includes <code>Kernel</code>. This was handled by special RDoc hack (which, basically, forcefully <a href="https://github.com/ruby/rdoc/blob/017bb9fa496ee0e0959facba694a053008d1ecb0/lib/rdoc/parser/c.rb#L477" class="external">reattached definition</a> of public methods if they are defined in <code>Kernel</code>, to <code>Object</code>)</li>
<li>The RDoc hack was working in C code only, so after introduction of <code>kernel.rb</code> the illusion started to crumble: methods like <code>#tap</code>, <code>#then</code>, <code>#class</code> <a href="https://docs.ruby-lang.org/en/3.2/Kernel.html" class="external">are now documented</a> as belonging to <code>Kernel</code> (breaking the tradition of public methods being documented in <code>Object</code>)</li>
<li>This is all inconsistent and confusing, and I believe, adds to friction both for newcomers and curious investigators of the language!</li>
</ol>
<p>Additionally, I believe:</p>
<ol>
<li>That the distinction of "two kinds of methods" is useful (saying from a practical experience with explaining Ruby while mentoring, writing articles, and discussing with colleagues)</li>
<li>But, considering everything, I agree with what <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/772">@Eregon (Benoit Daloze)</a> and <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/4">@nobu (Nobuyoshi Nakada)</a> say in <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Move public methods from Kernel to Object (Rejected)" href="https://bugs.ruby-lang.org/issues/19300">#19300</a>: pretending that methods belong not to the module they really belong to is not the optimal way to document things!</li>
</ol>
<p>So, the options I see (save for "do nothing and let things sort themselves somehow"):</p>
<ol>
<li>Change Ruby's implementation so public methods would really belong to <code>Object</code>. Actually, I don't believe anybody would agree to experiment on this scale, so just listing it here for completeness.</li>
<li>Just remove the RDoc hack; all methods would belong to <code>Kernel</code>, and maybe some introductory free-form text will instruct that they are different. <strong>Pro:</strong> Easy to do. <strong>Contra:</strong> The <code>Kernel</code> docs would be super-confusing.</li>
<li>Continue to maintain the hack in RDoc and extend it to <code>kernel.rb</code> (so methods like <code>#clone</code> and <code>#frozen?</code> would be still in <code>Object</code>). <strong>Pro:</strong> Relatively easy to do, will maintain structure many people used to. <strong>Contra:</strong> This is still a lie, methods belong to <code>Kernel</code>, not <code>Object</code>.</li>
<li>Adjust RDoc to a) be able to separately list <strong>public</strong> and <strong>private</strong> methods in two different lists, and add intro for <code>Kernel</code> explaining how to treat those. <strong>Pro:</strong> Probably the best correspondence to reality? <strong>Contra:</strong> Not sure how easy it is to change RDoc this way; and other renderers (like ruby-doc.com and rubyapi.org) would need to adjust themselves.</li>
</ol>
<p>So far, (4) looks the most reasonable (if (1) is 100% impossible, that is!)</p> Ruby master - Feature #19171 (Open): Update Unicode data to Unicode Version 15.1https://bugs.ruby-lang.org/issues/191712022-12-02T07:59:33Zduerst (Martin Dürst)duerst@it.aoyama.ac.jp
<p>According to <a href="http://blog.unicode.org/2022/11/the-unicode-standard-2023-release.html" class="external">http://blog.unicode.org/2022/11/the-unicode-standard-2023-release.html</a>, Unicode plans to release Version 15.1 in September 2023. According to <a href="https://www.unicode.org/versions/beta.html" class="external">https://www.unicode.org/versions/beta.html</a>, public alpha review starts Feb. 7, 2023, and ends April 4, 2023. Because alpha review may not include all the files we use, it may be difficult for us to participate.</p>
<p>Public beta review is planned to start May 23, 2023, ending July 4, 2023. At this point, we should be able to test things.</p> Ruby master - Bug #19154 (Open): Specify require and autoload guarantees in ractorshttps://bugs.ruby-lang.org/issues/191542022-11-26T23:52:22Zfxn (Xavier Noria)fxn@hashref.com
<p>Given a file <code>c.rb</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">C</span>
<span class="k">end</span>
</code></pre>
<p>the following script:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">r1</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="nb">require</span> <span class="s1">'./c.rb'</span>
<span class="k">end</span>
<span class="n">r2</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="nb">require</span> <span class="s1">'./c.rb'</span>
<span class="k">end</span>
<span class="n">r1</span><span class="p">.</span><span class="nf">take</span>
<span class="n">r2</span><span class="p">.</span><span class="nf">take</span>
</code></pre>
<p>raises:</p>
<pre><code>% ruby -v foo.rb
ruby 3.2.0preview3 (2022-11-27) [x86_64-darwin22]
foo.rb:1: warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues.
#<Thread:0x000000010fee2928 run> terminated with exception (report_on_exception is true):
#<Thread:0x00000001102acfe0 run> terminated with exception (report_on_exception is true):
<internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:164:in `ensure in require': can not access non-shareable objects in constant Kernel::RUBYGEMS_ACTIVATION_MONITOR by non-main ractor. (Ractor::IsolationError)
from <internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:167:in `require'
from foo.rb:6:in `block in <main>'
<internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:37:in `require'<internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:164:in `ensure in require': : can not access non-shareable objects in constant Kernel::RUBYGEMS_ACTIVATION_MONITOR by non-main ractor. (Ractor::IsolationError)
from <internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:167:in `require'
can not access non-shareable objects in constant Kernel::RUBYGEMS_ACTIVATION_MONITOR by non-main ractor. (Ractor::IsolationError) from foo.rb:2:in `block in <main>'
<internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:37:in `require': can not access non-shareable objects in constant Kernel::RUBYGEMS_ACTIVATION_MONITOR by non-main ractor. (Ractor::IsolationError)
from foo.rb:2:in `block in <main>'
from foo.rb:6:in `block in <main>'
<internal:ractor>:698:in `take': thrown by remote Ractor. (Ractor::RemoteError)
from foo.rb:9:in `<main>'
<internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:164:in `ensure in require': can not access non-shareable objects in constant Kernel::RUBYGEMS_ACTIVATION_MONITOR by non-main ractor. (Ractor::IsolationError)
from <internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:167:in `require'
from foo.rb:2:in `block in <main>'
<internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:37:in `require': can not access non-shareable objects in constant Kernel::RUBYGEMS_ACTIVATION_MONITOR by non-main ractor. (Ractor::IsolationError)
from foo.rb:2:in `block in <main>'
</code></pre>
<p>Would it be possible to have documentation about their interaction?</p>
<p>This is important also to understand autoloading within ractors, since constant references may trigger <code>require</code> calls.</p> Ruby master - Misc #19122 (Open): Use MADV_DONTNEED instead of MADV_FREE when freeing a Fiber's s...https://bugs.ruby-lang.org/issues/191222022-11-11T16:06:08Zsmcgivern (Sean McGivern)
<p>I'd like to propose that Ruby stops using MADV_FREE when freeing a Fiber's stack, and switches to using MADV_DONTNEED even when MADV_FREE is supported.</p>
<p>MADV_FREE is used in one place in the Ruby codebase, when freeing the stack of a freed Fiber: <a href="https://git.ruby-lang.org/ruby.git/tree/cont.c#n683" class="external">https://git.ruby-lang.org/ruby.git/tree/cont.c#n683</a></p>
<p>The comment for <code>fiber_pool_stack_free</code> says:</p>
<pre><code class="c syntaxhl" data-language="c"><span class="c1">// We advise the operating system that the stack memory pages are no longer being used.</span>
<span class="c1">// This introduce some performance overhead but allows system to relaim memory when there is pressure.</span>
</code></pre>
<p>Where possible (i.e. on Linux 4.5 and later), <code>fiber_pool_stack_free</code> uses <code>MADV_FREE</code> over <code>MADV_DONTNEED</code>. This has the side effect that memory statistics such as RSS will not reduce until and unless the OS actually reclaims that memory. If that doesn't happen, then the reported memory usage via RSS will be much higher than the 'real' memory usage.</p>
<p>If this was pervasive throughtout the Ruby codebase then that would be one thing, but currently this is just for Fiber. This means that:</p>
<ol>
<li>A program that doesn't use Fiber will have somewhat reliable RSS statistics on recent Linux.</li>
<li>A program that heavily uses Fiber (such as something using Async::HTTP) will see an inflated RSS statistic.</li>
</ol>
<p>Go made a similar change to the one I'm proposing here for similar reasons: <a href="https://github.com/golang/go/issues/42330" class="external">https://github.com/golang/go/issues/42330</a></p>
<blockquote>
<p>While <code>MADV_FREE</code> is somewhat faster than <code>MADV_DONTNEED</code>, it doesn't affect many of the statistics that <code>MADV_DONTNEED</code> does until the memory is actually reclaimed. This generally leads to poor user experience, like confusing stats in <code>top</code> and other monitoring tools; and bad integration with management systems that respond to memory usage.<br>
[...]<br>
I propose we change the default to prefer <code>MADV_DONTNEED</code> over <code>MADV_FREE</code>, to favor user-friendliness and minimal surprise over performance. I think it's become clear that Linux's implementation of <code>MADV_FREE</code> ultimately doesn't meet our needs.</p>
</blockquote>
<p>As an aside, MADV_FREE was not used in Ruby 3.1 (<a href="https://bugs.ruby-lang.org/issues/19101" class="external">https://bugs.ruby-lang.org/issues/19101</a>), and I haven't found any bugs filed about this behaviour other than that one.</p> Ruby master - Feature #19077 (Open): Introduce `Hash#dup` copy on write.https://bugs.ruby-lang.org/issues/190772022-10-22T21:55:25Zioquatix (Samuel Williams)samuel@oriontransfer.net
<p>Pull Request: <a href="https://github.com/ruby/ruby/pull/6613" class="external">https://github.com/ruby/ruby/pull/6613</a>.</p> Ruby master - Feature #19059 (Open): Introduce top level `module TimeoutError` for aggregating va...https://bugs.ruby-lang.org/issues/190592022-10-15T03:04:07Zioquatix (Samuel Williams)samuel@oriontransfer.net
<p>This proposal was originally part of <a href="https://bugs.ruby-lang.org/issues/18630" class="external">https://bugs.ruby-lang.org/issues/18630</a> but was removed because we could not decide on the name.</p>
<p>Introduce the following:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">TimeoutError</span>
<span class="k">end</span>
<span class="no">IO</span><span class="o">::</span><span class="no">TimeoutError</span><span class="p">.</span><span class="nf">include</span><span class="p">(</span><span class="no">TimeoutError</span><span class="p">)</span>
<span class="no">Regexp</span><span class="o">::</span><span class="no">TimeoutError</span><span class="p">.</span><span class="nf">include</span><span class="p">(</span><span class="no">TimeoutError</span><span class="p">)</span>
<span class="c1"># Maybe?</span>
<span class="no">Timeout</span><span class="o">::</span><span class="no">Error</span><span class="p">.</span><span class="nf">include</span><span class="p">(</span><span class="no">TimeoutError</span><span class="p">)</span>
</code></pre>
<p>It may be easier for users.</p>
<p>This was discussed before with the following conclusion:</p>
<ul>
<li>Top level <code>TimeoutError</code> is available.</li>
<li>Using a module for a <code>TimeoutError</code> may not be consistent with other top level <code>class #{thing}Error</code>.</li>
</ul> Ruby master - Feature #19056 (Open): Introduce `Fiber.annotation` for attaching messages to fibers.https://bugs.ruby-lang.org/issues/190562022-10-14T23:09:31Zioquatix (Samuel Williams)samuel@oriontransfer.net
<p>It's useful to know what a fiber is doing especially when they have a temporal execution (i.e. sockets connecting vs connected, binding vs accepting, queue popping, etc)</p>
<p>Let's introduce <code>Fiber.annotate</code> and <code>Fiber#annotation</code> for logging a short message attached to Fibers.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Fiber</span><span class="p">.</span><span class="nf">annotate</span> <span class="s2">"Counting to 10"</span>
<span class="mi">10</span><span class="p">.</span><span class="nf">times</span><span class="p">{</span><span class="o">|</span><span class="no">I</span><span class="o">|</span> <span class="nb">puts</span> <span class="no">I</span><span class="p">}</span>
<span class="c1"># Fiber.current.annotation => "Counting to 10"</span>
</code></pre>
<p>Pull Request: <a href="https://github.com/ruby/ruby/pull/6554" class="external">https://github.com/ruby/ruby/pull/6554</a></p> Ruby master - Bug #18818 (Open): Thread waitq does not retain referenced objects, can lead to use...https://bugs.ruby-lang.org/issues/188182022-06-05T21:39:16Znevans (Nicholas Evans)
<p>The attached script (and/or others like it) can cause SEGV in 3.0, 3.1, and master. It has always behaved as expected when I use <code>optflags=-O0</code>.</p>
<p>When I use it with <code>make run</code> on <code>master</code>:</p>
<pre><code>./miniruby -I../lib -I. -I.ext/common -r./x86_64-linux-fake ../test.rb
========================================================================
fiber_queue
completed in 0.00031349004711955786
========================================================================
fiber_sized_queue
../test.rb:62: [BUG] Segmentation fault at 0x0000000000000000
ruby 3.2.0dev (2022-06-05T06:18:26Z master 5ce0be022f) [x86_64-linux]
-- Control frame information -----------------------------------------------
c:0005 p:---- s:0023 e:000022 CFUNC :%
c:0004 p:0031 s:0018 e:000015 METHOD ../test.rb:62 [FINISH]
c:0003 p:---- s:0010 e:000009 CFUNC :pop
c:0002 p:0009 s:0006 e:000005 BLOCK ../test.rb:154 [FINISH]
c:0001 p:---- s:0003 e:000002 (none) [FINISH]
-- Ruby level backtrace information ----------------------------------------
../test.rb:154:in `block (2 levels) in <main>'
../test.rb:154:in `pop'
../test.rb:62:in `unblock'
../test.rb:62:in `%'
-- Machine register context ------------------------------------------------
RIP: 0x000055eae9ffa417 RBP: 0x00007f80aba855d8 RSP: 0x00007f80a9789598
RAX: 0x000000000000009b RBX: 0x00007f80a9789628 RCX: 0x00007f80ab9c37a0
RDX: 0x00007f80a97895c0 RDI: 0x0000000000000000 RSI: 0x000000000000009b
R8: 0x0000000000000000 R9: 0x00007f80a97895c0 R10: 0x0000000055550083
R11: 0x00007f80ac32ace0 R12: 0x00007f80aba855d8 R13: 0x00007f80ab9c3780
R14: 0x00007f80a97895c0 R15: 0x000000000000009b EFL: 0x0000000000010202
-- C level backtrace information -------------------------------------------
./miniruby(rb_vm_bugreport+0x5cf) [0x55eaea06b0ef]
./miniruby(rb_bug_for_fatal_signal+0xec) [0x55eae9e4fc2c]
./miniruby(sigsegv+0x4d) [0x55eae9fba30d]
[0x7f80ac153520]
./miniruby(rb_id_table_lookup+0x7) [0x55eae9ffa417]
./miniruby(callable_method_entry+0x103) [0x55eaea046bd3]
./miniruby(vm_respond_to+0x3f) [0x55eaea056c1f]
./miniruby(rb_check_funcall_default_kw+0x19c) [0x55eaea05788c]
./miniruby(rb_check_convert_type_with_id+0x8e) [0x55eae9f1b85e]
./miniruby(rb_str_format_m+0x1a) [0x55eae9fce82a]
./miniruby(vm_call_cfunc_with_frame+0x127) [0x55eaea041ac7]
./miniruby(vm_exec_core+0x114) [0x55eaea05d684]
./miniruby(rb_vm_exec+0x187) [0x55eaea04e747]
./miniruby(rb_funcallv_scope+0x1b0) [0x55eaea05a770]
./miniruby(rb_fiber_scheduler_unblock+0x3e) [0x55eae9fb979e]
./miniruby(sync_wakeup+0x10d) [0x55eae9ffd45d]
./miniruby(rb_szqueue_pop+0xf5) [0x55eae9ffefd5]
./miniruby(vm_call_cfunc_with_frame+0x127) [0x55eaea041ac7]
./miniruby(vm_exec_core+0x114) [0x55eaea05d684]
./miniruby(rb_vm_exec+0x187) [0x55eaea04e747]
./miniruby(rb_vm_invoke_proc+0x5f) [0x55eaea05584f]
./miniruby(rb_fiber_start+0x1da) [0x55eae9e1e24a]
./miniruby(fiber_entry+0x0) [0x55eae9e1e550]
</code></pre>
<p>I've attached the rest of the VM dump. <code>make runruby</code> gives a nearly identical dump. I can post a core dump or <code>rr</code> recording, if needed.<br>
_<br>
I'm sorry I didn't simplify the script more; small, seemingly irrelevant changes can change the failure or allow it to pass. Sometimes it raises a bizarre exception instead of SEGV, most commonly a NoMethodError which seemingly indicates that the local vars have been shifted or scrambled. For example, this particular SEGV was caused by a guard clause checking that <code>unblock(blocker, fiber)</code> was given a Fiber object. Here, that object is invalid, but I've seen it be a string or some other object from elsewhere in the process.</p>
<p>For comparison, this is what the script output should look like:</p>
<pre><code>========================================================================
fiber_queue
completed in 0.00031569297425448895
========================================================================
fiber_sized_queue
completed in 0.1176840600091964
========================================================================
fiber_sized_queue2
completed in 0.19209402799606323
========================================================================
fiber_sized_queue3
completed in 0.21404067997355014
========================================================================
fiber_sized_queue4
completed in 0.30277197097893804
</code></pre>
<p>I was attempting to create some simple benchmarks for <code>Queue</code> and <code>SizedQueue</code> with fibers, to mimic <code>benchmark/vm_thread_*queue*.rb</code>. I never completed the benchmarks because of this SEGV. :)</p> Ruby master - Misc #18761 (Open): provide an example wasm projecthttps://bugs.ruby-lang.org/issues/187612022-04-30T19:25:46Zgrosser (Michael Grosser)michael@grosser.it
<p>Neither the release notes nor the wasm/README.md include any runnable examples.<br>
Please provide a docker image that can be used to generate a wasm binary (even if it's just "hello world"),<br>
to show how this is supposed to work.</p> Ruby master - Bug #18740 (Open): Use of rightward assignment changes line number needed for line-...https://bugs.ruby-lang.org/issues/187402022-04-18T10:00:41Zhurricup (Alexandr Evstigneev)hurricup@gmail.com
<p>Affected ruby 3.1.1</p>
<p>Sample illustrating the problem (<code>test.rb</code>):</p>
<pre><code>def foo
File.read("test.rb")
.split("\n")
.map(&:strip)
.reject(&:empty?)
.first(10) => lines
puts lines
end
TracePoint.new(:line){ puts 'Hi' }.enable(target: RubyVM::InstructionSequence.of(method :foo), target_line: 2)
foo
</code></pre>
<p>produces</p>
<pre><code><internal:trace_point>:212:in `enable': can not enable any hooks (ArgumentError)
</code></pre>
<p>iseq for method:</p>
<pre><code>== disasm: #<ISeq:foo@/home/hurricup/test.rb:1 (1,0)-(9,3)> (catch: FALSE)
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 1] lines@0
0000 putnil ( 6)[LiCa]
0001 putnil
0002 putobject false
0004 putnil
0005 putnil
0006 opt_getinlinecache 15, <is:0> ( 2)
0009 putobject true
0011 getconstant :File
0013 opt_setinlinecache <is:0>
0015 putstring "test.rb"
0017 opt_send_without_block <calldata!mid:read, argc:1, ARGS_SIMPLE>
0019 putstring "\n" ( 3)
0021 opt_send_without_block <calldata!mid:split, argc:1, ARGS_SIMPLE>
0023 putobject :strip ( 4)
0025 send <calldata!mid:map, argc:0, ARGS_BLOCKARG>, nil
0028 putobject :empty? ( 5)
0030 send <calldata!mid:reject, argc:0, ARGS_BLOCKARG>, nil
0033 putobject 10 ( 6)
0035 opt_send_without_block <calldata!mid:first, argc:1, ARGS_SIMPLE>
0037 dup
0038 setlocal_WC_0 lines@0
0040 jump 88
0042 putspecialobject 1 ( 2)
0044 topn 4
0046 branchif 64
0048 putobject NoMatchingPatternError
0050 putspecialobject 1
0052 putobject "%p: %s"
0054 topn 4
0056 topn 7
0058 opt_send_without_block <calldata!mid:core#sprintf, argc:3, ARGS_SIMPLE>
0060 opt_send_without_block <calldata!mid:core#raise, argc:2, ARGS_SIMPLE>
0062 jump 84
0064 putobject NoMatchingPatternKeyError
0066 putspecialobject 1
0068 putobject "%p: %s"
0070 topn 4
0072 topn 7
0074 opt_send_without_block <calldata!mid:core#sprintf, argc:3, ARGS_SIMPLE>
0076 topn 7
0078 topn 9
0080 opt_send_without_block <calldata!mid:new, argc:3, kw:[matchee,key], KWARG>
0082 opt_send_without_block <calldata!mid:core#raise, argc:1, ARGS_SIMPLE>
0084 adjuststack 7
0086 jump 90
0088 adjuststack 6 ( 6)
0090 putself ( 8)[Li]
0091 getlocal_WC_0 lines@0
0093 opt_send_without_block <calldata!mid:puts, argc:1, FCALL|ARGS_SIMPLE>
0095 leave ( 9)[Re]
</code></pre>
<p>Works like a charm without <code>=> lines</code></p> Ruby master - Bug #18601 (Open): Invalid byte sequences in Big5 encodingshttps://bugs.ruby-lang.org/issues/186012022-02-22T22:15:06Zjanosch-x (Janosch Müller)
<p>I encoded all unicode codepoints in all encodings:</p>
<pre><code>full_string = ((0..0xD7FF).to_a + (0xE000..0x10FFFF).to_a).pack('U*'); 1
uniq_encodings =
Encoding.name_list -
Encoding.aliases.keys -
%w[locale external filesystem internal]
encoded_strings =
uniq_encodings.map do |enc|
full_string.encode(enc, invalid: :replace, undef: :replace, replace: '')
rescue => e
puts e
end; 1
</code></pre>
<p>This prints about 10 "converter not found" errors, such as <code>code converter not found (UTF-8 to UTF-7)</code>, but I guess this is expected.</p>
<p>Some of the converters seem to output invalid strings, though:</p>
<pre><code>encoded_strings.each do |str|
str&.codepoints
rescue => e
puts e
end; 1
</code></pre>
<p>This will print <code>invalid byte sequence in {Big5HKSCS,Big5-UAO,CP950,CP951}</code>.</p>
<p>Looking for example at the generated CP950 string, 8031 of its 25342 characters are invalid, spread across 2017 distinct ranges in the string. The invalid characters' codepoints are all in the range of 0x81..0xFE.</p>
<p>Is this a bug?</p>
<p>I would expect <code>String#encode</code> with <code>invalid: :replace, undef: :replace</code> not to create invalid byte sequences, but maybe I am misunderstanding these encodings and this is an unavoidable issue?</p>
<p>CC <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/50">@duerst (Martin Dürst)</a></p> Ruby master - Feature #18275 (Open): Add an option to define_method to not capture the surroundin...https://bugs.ruby-lang.org/issues/182752021-10-27T19:27:45Zvinistock (Vinicius Stock)
<p>Invoking <code>define_method</code> will capture the surrounding environment, making sure we have access to anything defined in that surrounding scope. However, that’s not always necessary. There are uses for <code>define_method</code> where the surrounding environment is not needed.</p>
<p>Always capturing the surrounding environment slows down even the methods that don’t need access to it. Additionally, it prevents methods created using <code>define_method</code> to exist in all Ractors in a program.</p>
<p>If we could add an option to disable capturing the surrounding environment for <code>define_method</code>, we could make it so that it creates the dynamic method in all Ractors.</p>
<p>There could also be some performance benefits for the usages that do not need the surrounding environment. By not having to keep references to the surrounding scope, the GC could let go of locals from that environment, which might benefit GC as well.</p>
<p>Another option could be to accept the list of locals that the <code>define_method</code> invocation will need, as a way of letting go of references that are no longer needed.</p>
<p>Examples:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># Current behavior</span>
<span class="c1">#</span>
<span class="c1"># All of the surrounding environment is captured and references are kept for the locals</span>
<span class="c1"># The method created only exists in the current Ractor, due to possible references to the captured variables</span>
<span class="n">some_random_thing</span> <span class="o">=</span> <span class="s2">"a"</span> <span class="o">*</span> <span class="mi">10000</span>
<span class="n">some_captured_block</span> <span class="o">=</span> <span class="o">-></span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
<span class="n">define_method</span><span class="p">(</span><span class="ss">:my_method</span><span class="p">,</span> <span class="o">&</span><span class="n">some_captured_block</span><span class="p">)</span>
</code></pre>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># Enable/disable all option</span>
<span class="c1">#</span>
<span class="c1"># Add an option that allows disabling capturing the surrounding environment completely</span>
<span class="c1"># The method created exists in all Ractors and none of the references are kept</span>
<span class="n">some_random_thing</span> <span class="o">=</span> <span class="s2">"a"</span> <span class="o">*</span> <span class="mi">10000</span>
<span class="n">some_captured_block</span> <span class="o">=</span> <span class="o">-></span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
<span class="n">define_method</span><span class="p">(</span><span class="ss">:my_method</span><span class="p">,</span> <span class="ss">capture_environment: </span><span class="kp">false</span><span class="p">,</span> <span class="o">&</span><span class="n">some_captured_block</span><span class="p">)</span>
</code></pre>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># Choose variables option</span>
<span class="c1">#</span>
<span class="c1"># Add an option that allows indicating which locals are needed for a define_method invocation</span>
<span class="c1"># The method created exists in all Ractors if no locals are needed</span>
<span class="c1"># The method is created only in the current Ractor if at least one local is needed</span>
<span class="c1"># All “unneeded” locals are let go</span>
<span class="n">some_random_thing</span> <span class="o">=</span> <span class="s2">"a"</span> <span class="o">*</span> <span class="mi">10000</span> <span class="c1"># kept because `my_method` needs it</span>
<span class="n">another_random_thing</span> <span class="o">=</span> <span class="s2">"b"</span> <span class="o">*</span> <span class="mi">10000</span> <span class="c1"># not kept</span>
<span class="n">some_captured_block</span> <span class="o">=</span> <span class="o">-></span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
<span class="n">define_method</span><span class="p">(</span><span class="ss">:my_method</span><span class="p">,</span> <span class="ss">needs: </span><span class="p">[</span><span class="ss">:some_random_thing</span><span class="p">],</span> <span class="o">&</span><span class="n">some_captured_block</span><span class="p">)</span>
</code></pre> Ruby master - Feature #18227 (Open): Static class initialization.https://bugs.ruby-lang.org/issues/182272021-09-27T03:49:35Zioquatix (Samuel Williams)samuel@oriontransfer.net
<p>As a follow on from <a href="https://bugs.ruby-lang.org/issues/18189" class="external">https://bugs.ruby-lang.org/issues/18189</a> I would like to propose some kind of static class initialization. I'll investigate whether it's possible and create a PR.</p> Ruby master - Bug #18002 (Open): s390x: Tests failing without LC_ALL envhttps://bugs.ruby-lang.org/issues/180022021-06-21T10:45:16Zjaruga (Jun Aruga)
<p>The following failures happened in RubyCI on our s390x Ubuntu focal server.<br>
On the server, RubyCI (ruby/chkbuild) is executed with LC_ALL not set, by cron.<br>
I found the unset <code>LC_ALL</code> causes the failures on the s390x server. This does not happen on x86_64 Fedora 33 on my local machine.</p>
<p>I was able to reproduce the failures on the master branch <code>dbd1887d04f5ff7c2a1f0a27d7339133a</code> on the server.</p>
<a name="Reproducer"></a>
<h2 >Reproducer<a href="#Reproducer" class="wiki-anchor">¶</a></h2>
<pre><code>$ uname -m
s390x
$ autoconf
$ ./configure \
--prefix=${HOME}/local/ruby-master-9d96837 \
--enable-shared
$ make
</code></pre>
<h3>Without <code>LC_ALL</code>
</h3>
<p>Then run the tests without <code>LC_ALL</code>.</p>
<pre><code>$ unset LC_ALL
$ echo $LC_ALL
<= empty
</code></pre>
<pre><code>$ make test-all TESTS="-v test/ruby/test_file.rb -n TestFile#test_realpath_encoding"
Run options:-
--seed=85060
"--ruby=./miniruby -I./lib -I. -I.ext/common ./tool/runruby.rb --extout=.ext -- --disable-gems"
--excludes-dir=./test/excludes
--name=!/memory_leak/
-v
-n
TestFile#test_realpath_encoding
# Running tests:
[1/0] TestFile#test_realpath_encoding = 0.00 s
1) Failure:
TestFile#test_realpath_encoding [/home/jaruga/git/ruby/ruby2/test/ruby/test_file.rb:284]:
<"/tmp/rubytest-realpath20210621-3365652-za1wql/A\u0391\u0410\u0531\u10A0\u05D0\u2C00\u3042"> expected but was
<"/tmp/rubytest-realpath20210621-3365652-za1wql/A\u00CE\u0091\u00D0\u0090\u00D4\u00B1\u00E1\u0082\u00A0\u00D7\u0090\u00E2\u00B0\u0080\u00E3\u0081\u0082">.
Finished tests in 0.007217s, 138.5674 tests/s, 692.8372 assertions/s.
1 tests, 5 assertions, 1 failures, 0 errors, 0 skips
ruby -v: ruby 3.1.0dev (2021-06-18T10:13:36Z master 9d96837dbd) [s390x-linux]
make: *** [uncommon.mk:803: yes-test-all] Error 1
</code></pre>
<pre><code>$ make test-all TESTS="-v test/irb/test_context.rb -n TestIRB::TestContext#test_eval_input_with_invalid_byte_sequence_exception"
Run options:-
--seed=74635
"--ruby=./miniruby -I./lib -I. -I.ext/common ./tool/runruby.rb --extout=.ext -- --disable-gems"
--excludes-dir=./test/excludes
--name=!/memory_leak/
-v
-n
TestIRB::TestContext#test_eval_input_with_invalid_byte_sequence_exception
# Running tests:
[1/0] TestIRB::TestContext#test_eval_input_with_invalid_byte_sequence_exception = 0.00 s
1) Failure:
TestIRB::TestContext#test_eval_input_with_invalid_byte_sequence_exception [/home/jaruga/git/ruby/ruby2/test/irb/test_context.rb:505]:
Expected /\(irb\):1:in `fuga': A\\xF3B \(RuntimeError\)\n/
to match
"(irb):1:in `fuga': A�B (RuntimeError)\n"+
"\tfrom (irb):1:in `hoge'\n"+
"\tfrom (irb):1:in `<main>'\n"
after 1 patterns with 0 characters.
Finished tests in 0.007640s, 130.8819 tests/s, 785.2916 assertions/s.
1 tests, 6 assertions, 1 failures, 0 errors, 0 skips
ruby -v: ruby 3.1.0dev (2021-06-18T10:13:36Z master 9d96837dbd) [s390x-linux]
make: *** [uncommon.mk:803: yes-test-all] Error 1
</code></pre>
<h3>With <code>export LC_ALL=C</code>
</h3>
<p>On the <code>export LC_ALL=C</code> (<code>LC_ALL=C</code> without <code>export</code> is not enough to pass the tests)</p>
<pre><code>$ export LC_ALL=C
$ echo $LC_ALL
C
</code></pre>
<pre><code>$ make test-all TESTS="-v test/ruby/test_file.rb -n TestFile#test_realpath_encoding"
Run options:
--seed=89696
"--ruby=./miniruby -I./lib -I. -I.ext/common ./tool/runruby.rb --extout=.ext -- --disable-gems"
--excludes-dir=./test/excludes
--name=!/memory_leak/
-v
-n
TestFile#test_realpath_encoding
# Running tests:
[1/0] TestFile#test_realpath_encoding = 0.00 s
Finished tests in 0.004715s, 212.0691 tests/s, 1060.3455 assertions/s.
1 tests, 5 assertions, 0 failures, 0 errors, 0 skips
ruby -v: ruby 3.1.0dev (2021-06-18T10:13:36Z master 9d96837dbd) [s390x-linux]
</code></pre>
<pre><code>$ make test-all TESTS="-v test/irb/test_context.rb -n TestIRB::TestContext#test_eval_input_with_invalid_byte_sequence_exception"
Run options:
--seed=67965
"--ruby=./miniruby -I./lib -I. -I.ext/common ./tool/runruby.rb --extout=.ext -- --disable-gems"
--excludes-dir=./test/excludes
--name=!/memory_leak/
-v
-n
TestIRB::TestContext#test_eval_input_with_invalid_byte_sequence_exception
# Running tests:
[1/0] TestIRB::TestContext#test_eval_input_with_invalid_byte_sequence_exception = 0.00 s
Finished tests in 0.007877s, 126.9448 tests/s, 761.6689 assertions/s.
1 tests, 6 assertions, 0 failures, 0 errors, 0 skips
ruby -v: ruby 3.1.0dev (2021-06-18T10:13:36Z master 9d96837dbd) [s390x-linux]
</code></pre>
<a name="Possible-Solution"></a>
<h2 >Possible Solution<a href="#Possible-Solution" class="wiki-anchor">¶</a></h2>
<p>Fix the tests not depending on the external LC_ALL condition.</p> Ruby master - Bug #17996 (Open): Cygwin: thread + pipe behavior since Ruby 2.6https://bugs.ruby-lang.org/issues/179962021-06-17T03:59:49Zxtkoba (Tee KOBAYASHI)
<p>The following one-liner is the repro named <code>thread-pipe-read-close.rb</code> the aim of which is essentially the same as that of "IO#close raises an IOError with a clear message" test in <code>spec/ruby/core/io/close_spec.rb</code>.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">r</span><span class="p">,</span> <span class="n">w</span> <span class="o">=</span> <span class="no">IO</span><span class="p">.</span><span class="nf">pipe</span><span class="p">;</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">new</span><span class="p">{</span> <span class="n">r</span><span class="p">.</span><span class="nf">read</span> <span class="p">};</span> <span class="nb">sleep</span> <span class="mf">0.5</span><span class="p">;</span> <span class="n">r</span><span class="p">.</span><span class="nf">close</span>
</code></pre>
<p>Run on Cygwin with Ruby 2.6 or later, this hangs up indefinitely consuming a full core. On the other hand, with Ruby 2.5.9p229 it works as expected.</p>
<pre><code>$ miniruby25 -v
ruby 2.5.9p229 (2021-04-05 revision 67939) [x86_64-cygwin]
$ miniruby25 thread-pipe-read-close.rb
#<Thread:0x000000080006c9f0@thread-pipe-read-close.rb:2 run> terminated with exception (report_on_exception is true):
Traceback (most recent call last):
1: from thread-pipe-read-close.rb:2:in `block in <main>'
thread-pipe-read-close.rb:2:in `read': IOError
$ miniruby -v
ruby 3.1.0dev (2021-06-10T23:31:51Z master 9210f8df7f) [x86_64-cygwin]
$ miniruby thread-pipe-read-close.rb
</code></pre> Ruby master - Feature #17884 (Open): locindex for profiling toolshttps://bugs.ruby-lang.org/issues/178842021-05-24T15:41:17Zko1 (Koichi Sasada)
<p>(MRI internals)</p>
<p>Profiling tools need to record the code location, mainly a pair of file path and line number ("file:line").<br>
To record this pair in 64bit CPU, 8B (VALUE) + 4B (int) = 12B is needed. In general, the number of pairs (file:line) in a interpreter process does not exceed 32bit boundary (4G pairs). <code>st_data_t</code> is 8B (or 4B on 32bit CPU) and we can not store "file:path" information as <code>st_table</code> key/value.</p>
<p>Also getting a line from PC (program counter), is not simple (now we are using succinct bitvector, enough fast and compact data in general, but need some calculations).</p>
<p>To solve the size and the time problem, we introduced new concept "locindex".</p>
<p>"locindex" is <code>unsigned int</code> data structure, maybe 4B in many environments. A "locindex" represents a pair of "iseq" and "PC" (more correctly, "pc_index", given by <code>PC - iseq->body->iseq_encoded</code>).</p>
<p>We can get "locindexL" from "iseqA" with "pcB". "iseqA" will not be freed in this process.<br>
From "locindexL", we can get "iseqA" and "pcB". We can calculate "file:line" information from the iseq/pc pair. "file:line" information is needed to see the profiling results, so the performance of getting "file:line" from a "iseq/pc" pair is not important, in many cases.</p>
<p>"locindex" is calculated by the following pseudo code:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="vg">$last_locindex</span> <span class="o">=</span> <span class="mi">1</span>
<span class="vg">$global_recorded_ary</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">def</span> <span class="nf">locindex</span> <span class="n">iseq</span><span class="p">,</span> <span class="n">pc</span> <span class="c1"># pc is pc_index (nth instruction)</span>
<span class="k">if</span> <span class="n">iseq</span><span class="o">-></span><span class="n">locindex_start</span> <span class="o">==</span> <span class="mi">0</span> <span class="c1"># not recorded yet</span>
<span class="n">iseq</span><span class="o">-></span><span class="n">locindex_start</span> <span class="o">=</span> <span class="n">last_locindex</span>
<span class="vg">$last_locindex</span> <span class="o">+=</span> <span class="n">iseq</span><span class="o">-></span><span class="n">iseq_size</span>
<span class="vg">$global_recorded_ary</span><span class="p">.</span><span class="nf">push</span><span class="p">(</span><span class="n">iseq</span><span class="p">)</span>
<span class="k">end</span>
<span class="n">iseq</span><span class="o">-></span><span class="n">locindex_start</span> <span class="o">+</span> <span class="n">pc</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">resolve</span> <span class="n">locindex</span>
<span class="vg">$global_recorded_ary</span><span class="p">.</span><span class="nf">each</span><span class="p">{</span><span class="o">|</span><span class="n">iseq</span><span class="o">|</span>
<span class="k">if</span> <span class="n">locindex</span> <span class="n">is</span> <span class="k">in</span> <span class="n">iseq?</span>
<span class="k">return</span> <span class="p">[</span><span class="n">iseq</span><span class="p">,</span> <span class="n">locindx</span> <span class="o">-</span> <span class="n">iseq</span><span class="o">-></span><span class="n">locindex_start</span><span class="p">]</span>
<span class="k">end</span>
<span class="p">}</span>
<span class="k">end</span>
</code></pre>
<hr>
<p><code>ObjectSpace.trace_object_allocations</code> is one of profiling tool and we can use "locindex" to make it.<br>
I implemented and measure the performance.</p>
<p>The benchmark program:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># This file should be located to the ruby's src directory</span>
<span class="nb">require</span> <span class="s1">'objspace/trace'</span>
<span class="nb">require</span> <span class="s1">'rdoc/rdoc'</span>
<span class="nb">require</span> <span class="s1">'tmpdir'</span>
<span class="n">srcdir</span> <span class="o">=</span> <span class="no">File</span><span class="p">.</span><span class="nf">expand_path</span><span class="p">(</span><span class="n">__dir__</span><span class="p">)</span>
<span class="no">STDERR</span><span class="p">.</span><span class="nf">puts</span> <span class="n">srcdir</span>
<span class="no">Dir</span><span class="p">.</span><span class="nf">mktmpdir</span><span class="p">(</span><span class="s1">'rdocbench-'</span><span class="p">){</span><span class="o">|</span><span class="n">d</span><span class="o">|</span>
<span class="n">dir</span> <span class="o">=</span> <span class="no">File</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="s1">'rdocbench'</span><span class="p">)</span>
<span class="n">args</span> <span class="o">=</span> <span class="sx">%W(--root </span><span class="si">#{</span><span class="n">srcdir</span><span class="si">}</span><span class="sx"> --page-dir </span><span class="si">#{</span><span class="n">srcdir</span><span class="si">}</span><span class="sx">/doc --encoding=UTF-8 --no-force-update --all --ri --debug --quiet </span><span class="si">#{</span><span class="n">srcdir</span><span class="si">}</span><span class="sx">)</span>
<span class="n">args</span> <span class="o"><<</span> <span class="s1">'--op'</span> <span class="o"><<</span> <span class="n">dir</span>
<span class="n">r</span> <span class="o">=</span> <span class="no">RDoc</span><span class="o">::</span><span class="no">RDoc</span><span class="p">.</span><span class="nf">new</span>
<span class="n">r</span><span class="p">.</span><span class="nf">document</span> <span class="n">args</span>
<span class="p">}</span>
</code></pre>
<p>Results:</p>
<pre><code># without 'objspace/trace'
real 0m19.764s
user 0m19.200s
sys 0m0.561s
# with 'objspace/trace'
real 0m42.638s
user 0m41.695s
sys 0m0.920s
# with 'objspace/trace' and locindex
real 0m36.875s
user 0m35.956s
sys 0m0.890s
# with 'objspace/trace' light mode
real 0m27.743s
user 0m26.921s
sys 0m0.820s
</code></pre>
<p>Light mode is only recording "locindex".<br>
I believe that most of case it is enough to see the "file:line" pair for performance tuning.</p>
<p>Implementation: <a href="https://github.com/ruby/ruby/pull/4524/" class="external">https://github.com/ruby/ruby/pull/4524/</a><br>
"light-mode" seems more practical.</p> Ruby master - Feature #17849 (Open): Fix Timeout.timeout so that it can be used in threaded Web s...https://bugs.ruby-lang.org/issues/178492021-05-05T01:41:09Zduerst (Martin Dürst)duerst@it.aoyama.ac.jp
<p>Making this a separate issue from <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Add support for Regexp timeouts (Closed)" href="https://bugs.ruby-lang.org/issues/17837">#17837</a></p>
<p>Eregon (Benoit Daloze) wrote in <a href="https://bugs.ruby-lang.org/issues/17837#note-10" class="external">https://bugs.ruby-lang.org/issues/17837#note-10</a> (which is about timeouts for regular expressions):</p>
<blockquote>
<p>I think fixing Timeout.timeout might be possible.<br>
The main/major issue is it can trigger within <code>ensure</code>, right? Is there anything else?<br>
We could automatically mask <code>Thread#raise</code> within <code>ensure</code> so it only happens after the <code>ensure</code> body completes.<br>
And we could still have a larger "hard timeout" if an <code>ensure</code> takes way too long (shouldn't happen, but one cannot be sure).<br>
I recall discussing this with <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/6346">@schneems (Richard Schneeman)</a> some time ago on Twitter.</p>
</blockquote> Ruby master - Feature #17830 (Open): Add Integer#previous and Integer#prev https://bugs.ruby-lang.org/issues/178302021-04-26T17:27:05Zrafasoares (Rafael Soares)rafasoaresms@gmail.com
<p>I think <code>Integer#pred</code> is great as the inverse of <code>#succ</code>, but it reads a bit weird as the inverse of <code>#next</code>, which might be preferable for those going for a more "reads like English" approach.</p>
<p>On that note, <code>#previous</code> reads better, but it's also twice as long as <code>#pred</code> (or even <code>#next</code>). Which is why I've also added the shorthand <code>#prev</code></p>
<p>Since Ruby strives for readability, I always thought it was weird that the team omitted this improvement.</p>
<p>Also, I thought about writing a gem for this, but:</p>
<ol>
<li>Do we really want to add another gem for such a simple change to every project?</li>
<li>Monkey-patching gems feel dirty.</li>
</ol>
<p>Finally, I want to mention that I tried looking for previous discussions on this topic, as it seems likely someone would've brought this up at some point, but was unsuccessful. Probably due to the massive amount of baggage in the core issue tracker and mailing lists, I could've missed something among the noise.</p>
<p>I've created a fork on GitHub (<a href="https://github.com/rafasoares/ruby/commit/05119848b1f480db2e809f964528799030cc7ebb" class="external">https://github.com/rafasoares/ruby/commit/05119848b1f480db2e809f964528799030cc7ebb</a>) in order to open a PR, but decided to open this ticket as well, after reading the contributing guide more carefully.</p> Ruby master - Feature #17785 (Open): Allow named parameters to be keywordshttps://bugs.ruby-lang.org/issues/177852021-04-08T15:08:40Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>We should allow named parameters to be keywords and use add a trailing <code>_</code> to the corresponding variable:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">check</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="k">class</span><span class="p">:)</span>
<span class="n">arg</span><span class="p">.</span><span class="nf">is_a?</span><span class="p">(</span><span class="n">class_</span><span class="p">)</span>
<span class="k">end</span>
<span class="n">check</span><span class="p">(</span><span class="mi">42</span><span class="p">,</span> <span class="ss">class: </span><span class="no">Integer</span><span class="p">)</span> <span class="c1"># => true</span>
</code></pre>
<p>Currently, if we want such an API we have to use <code>**rest</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">check</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">rest</span><span class="p">)</span>
<span class="n">class_</span> <span class="o">=</span> <span class="n">rest</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="ss">:class</span><span class="p">)</span> <span class="p">{</span> <span class="k">raise</span> <span class="no">ArgumentError</span><span class="p">(</span><span class="s1">'missing keyword: :class'</span><span class="p">)}</span>
<span class="k">if</span> <span class="n">rest</span><span class="p">.</span><span class="nf">size</span> <span class="o">></span> <span class="mi">1</span>
<span class="n">unknown</span> <span class="o">=</span> <span class="n">rest</span><span class="p">.</span><span class="nf">keys</span> <span class="o">-</span> <span class="p">[</span><span class="ss">:class</span><span class="p">]</span>
<span class="k">raise</span> <span class="no">ArgumentError</span><span class="p">(</span><span class="s2">"unknown keyword(s): :</span><span class="si">#{</span><span class="n">unknown</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s1">', :'</span><span class="p">)</span><span class="si">}</span><span class="s2">)
end
arg.is_a?(class_)
end
</span></code></pre>
<p>This is very verbose, much less convenient, much less readable, prevents <code>steep</code> from generating the proper signature, etc.</p>
<p>We should do the same for pattern match.</p> Ruby master - Bug #17624 (Open): Ractor.receive is not thread-safehttps://bugs.ruby-lang.org/issues/176242021-02-13T02:14:53Zdazuma (Daniel Azuma)dazuma@gmail.com
<p>It does not seem to be possible to have multiple blocked <code>Ractor.receive</code> calls concurrently in the same Ractor (but different threads). One may succeed but the others will hang indefinitely, even if messages are present in the queue.</p>
<p>Example code below. It does the following:</p>
<ol>
<li>Starts a Ractor <code>r1</code> that spawns two "listener threads". Each thread calls <code>Ractor.receive</code>, which blocks waiting for messages.</li>
<li>The main Ractor pauses briefly to ensure that the threads have started, and then sends two messages to the Ractor <code>r1</code>, with the expectation that each thread will receive one of them.</li>
<li>What actually happens is, the <code>Ractor.receive</code> call in <em>one</em> of the threads will pick a message and return. However, the <code>Ractor.receive</code> call in the other thread remains blocked, even though the second message is in the queue.</li>
<li>Ractor <code>r1</code>, after a pause to ensure that both messages have been sent, issues another <code>Ractor.receive</code> call. This call does not block (because the second message is in the queue), and successfully returns the message. Meanwhile, the second thread's <code>Ractor.receive</code> call remains blocked. This demonstrates that the second message has been sent successfully and is receivable, even though the second thread still hasn't returned it. It appears that the second thread's receive call is in a bad state.</li>
</ol>
<pre><code>r1 = Ractor.new do
# Start two listener threads
t1 = Thread.new do
puts "T1 received #{Ractor.receive}"
end
t2 = Thread.new do
puts "T2 received #{Ractor.receive}"
end
# Pause to ensure that both messages have been sent.
# (One of the messages will have been picked up by a
# thread, but the other remains in the queue.)
sleep(3)
# Receive the second message. This will succeed, even
# though the second thread is still blocked.
puts "Later received #{Ractor.receive}"
# Wait for the threads to finish.
# This will never complete because one of the threads will not
# receive the second message, and is still blocking.
[t1, t2].each(&:join)
:ok
end
# Make sure both receive calls are blocking
sleep(1)
# Send two messages.
r1.send(1)
r1.send(2)
# This never returns because the ractor never completes.
puts r1.take
</code></pre>
<p>This happens both in 3.0.0 release and on 3.1.0 head.</p>
<pre><code>% ruby -v
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin20]
</code></pre>
<pre><code>% ruby -v
ruby 3.1.0dev (2021-02-09T13:22:37Z master e7a831de8e) [x86_64-darwin20]
</code></pre>
<p>Notes:</p>
<ul>
<li>This also happens when using <code>receive_if</code>.</li>
<li>I would expect this use case to be common when writing a Ractor that contains multiple thread-safe "workers". (This was in fact the use case I was trying to implement when I encountered this issue.) Thus, if we decide this is working as intended, we should document it, and possibly suggest to users that they write their Ractor to funnel communication through a single dedicated thread.</li>
</ul> Ruby master - Bug #17617 (Open): When a Ractor's incoming port is closed, Ractor.receive_if does ...https://bugs.ruby-lang.org/issues/176172021-02-09T16:24:27Zdazuma (Daniel Azuma)dazuma@gmail.com
<p>If Ractor#close_incoming is called on a Ractor, any pending Ractor.receive call will raise Ractor::ClosedError. However, any pending Ractor.receive_if call will not; instead, it never returns.</p>
<pre><code>r1 = Ractor.new do
Ractor.receive
rescue => e
e
end
r1.close_incoming
result = r1.take
puts "**** taken: #{result}" # displays the Ractor::ClosedError
r2 = Ractor.new do
Ractor.receive_if { true }
puts "**** never reaches here"
rescue => e
puts "**** never reaches here"
e
end
r2.close_incoming
puts "**** hangs here..."
r2.take
puts "**** never reaches here"
</code></pre>
<p>This was tested against both 3.0.0 and 3.1.0 head, with the same result.</p>
<pre><code>% ruby -v
ruby 3.1.0dev (2021-02-09T13:22:37Z master e7a831de8e) [x86_64-darwin20]
</code></pre>
<pre><code>% ruby -v
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin20
</code></pre>
<p>I have also tried including sleep statements to force the Ractor.receive_if to execute both before and after the Ractor#close_incoming call. The result is the same either way. receive_if hangs regardless of whether the incoming port is already closed when receive_if is invoked, or whether the port is closed while the receive_if is already blocking.</p> Ruby master - Misc #17569 (Open): `uri` lib maintainershiphttps://bugs.ruby-lang.org/issues/175692021-01-22T15:48:33Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I’d like to merge <a href="https://github.com/ruby/uri/pull/15" class="external">https://github.com/ruby/uri/pull/15</a> but it is an API change. I would release v1.0.0. <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/271">@akr (Akira Tanaka)</a> is the official maintainer of <code>uri</code>… Is he still interested in this role? Otherwise we could put “Ruby core team” in the listing…</p> Ruby master - Feature #17525 (Open): Implement Happy Eyeballs Version 2 (RFC8305) in Socket.tcphttps://bugs.ruby-lang.org/issues/175252021-01-10T13:17:37ZGlass_saga (Masaki Matsushita)glass.saga@gmail.com
<p><a href="https://github.com/ruby/ruby/pull/4038" class="external">https://github.com/ruby/ruby/pull/4038</a></p>
<p>This change implements Happy Eyeballs Version 2 (RFC8305) in Socket.tcp.<br>
It enables fallback from IPv6 to IPv4 without a long waiting time.</p> Ruby master - Feature #17513 (Open): Methods of shareable objects and UnboundMethods should be sh...https://bugs.ruby-lang.org/issues/175132021-01-06T06:04:18Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Foo</span>
<span class="k">def</span> <span class="nf">foo</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">f</span> <span class="o">=</span> <span class="no">Foo</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">freeze</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">shareable?</span><span class="p">(</span><span class="n">f</span><span class="p">)</span> <span class="c1"># => true</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">make_shareable</span><span class="p">(</span><span class="n">f</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:foo</span><span class="p">).</span><span class="nf">to_proc</span><span class="p">)</span> <span class="c1"># => Proc, ok</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">make_shareable</span><span class="p">(</span><span class="n">f</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:foo</span><span class="p">))</span> <span class="c1"># => Ractor::Error, expected Method</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">make_shareable</span><span class="p">(</span><span class="no">Foo</span><span class="p">.</span><span class="nf">instance_method</span><span class="p">(</span><span class="ss">:foo</span><span class="p">))</span> <span class="c1"># => Ractor::Error, expected UnboundMethod</span>
</code></pre> Ruby master - Misc #17502 (Open): C vs Rubyhttps://bugs.ruby-lang.org/issues/175022021-01-02T20:25:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Some features are coded in a mix of Ruby and C (e.g. ractor.rb).</p>
<p>External gems don't have access to this. The C-API to deal with keyword parameters is also very verbose the parsing and the engine does not know it.</p>
<p>Moreover, some optimization PRs are simply rewriting C-code into Ruby using pseudo C code.</p>
<p>I understand the intentions are great, but changes like <a href="https://github.com/ruby/ruby/pull/4018/files" class="external">https://github.com/ruby/ruby/pull/4018/files</a> seem a symptom that something needs to be improved with the C api.</p>
<pre><code class="diff syntaxhl" data-language="diff"><span class="gd">-static VALUE
- flo_zero_p(VALUE num)
- {
- return flo_iszero(num) ? Qtrue : Qfalse;
- }
</span># in different file:
<span class="gi">+ def zero?
+ Primitive.attr! 'inline'
+ Primitive.cexpr! 'flo_iszero(self) ? Qtrue : Qfalse'
+ end
</span></code></pre>
<p>It seems to me that this is a way to circumvent a deeper issue. Is this the right direction?</p>
<p>Is there a plan for an API that would:</p>
<ol>
<li>be accessible to C extensions</li>
<li>can't be re-written any faster in pseuso-C in Ruby</li>
<li>has an easy way to define keyword parameters?</li>
</ol>
<p>I realize that RBS may give perfect signatures, but ideally <code>parameters</code> would be more informative for C-functions too.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Ractor</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:yield</span><span class="p">).</span><span class="nf">parameters</span>
<span class="c1"># => [[:req, :obj], [:key, :move]] # good!</span>
<span class="no">Fiber</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:initialize</span><span class="p">).</span><span class="nf">parameters</span>
<span class="c1"># => [[:rest]] # not good, should be [[:key, :blocking]]</span>
</code></pre> Ruby master - Feature #17473 (Open): Make Pathname to embedded class of Rubyhttps://bugs.ruby-lang.org/issues/174732020-12-26T12:00:42Zhsbt (Hiroshi SHIBATA)hsbt@ruby-lang.org
<p>pathname is one of most useful utility class of Ruby. I'm happy to use Pathname without require it.</p>
<p>Any thought?</p> Ruby master - Bug #17420 (Open): Unsafe mutation of $" when doing non-RubyGems require in Ractorhttps://bugs.ruby-lang.org/issues/174202020-12-21T18:31:49ZEregon (Benoit Daloze)
<p>With an empty file <code>a.rb</code>:</p>
<pre><code>$ ruby --disable-gems -e 'Ractor.new { puts $" }.take'
-e:1:in `block in <main>': can not access global variables $" from non-main Ractors (RuntimeError)
</code></pre>
<p>That is expected, given the rules for global variables.</p>
<pre><code>ruby --disable-gems -e 'Ractor.new { require "./a.rb"; }.take; p $"'
[... , "/home/eregon/a.rb"]
</code></pre>
<p>Is it OK that the Ractor can do <code>require</code>, which does modify <code>$"</code>?</p>
<p>I think it's not, and it might lead to segfaults if e.g. the main Ractor mutates <code>$"</code> in parallel to some other Ractor doing <code>require</code>.</p>
<p>Probably <code>require</code> needs to be forbidden in non-main Ractors (it does mutate <code>$"</code>, so it's logical), or there needs to be always VM-global synchronization on any access to <code>$"</code> (otherwise, segfaults are possible).<br>
The latter doesn't seem reasonable, especially when considering the user might do <code>$".each { ... }</code>.</p>
<hr>
<p>Note that RubyGems' <code>require</code> does not work on non-main Ractors (pretty much expected given it depends on a lot of global state):</p>
<pre><code>$ ruby -e 'Ractor.new { require "./a.rb"; }.take'
<internal:/home/eregon/prefix/ruby-master/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:37:in `require': can not access non-shareable objects in constant Kernel::RUBYGEMS_ACTIVATION_MONITOR by non-main ractor. (NameError)
</code></pre>
<p>This probably also has consequences for <code>autoload</code>.<br>
Maybe the <code>zeitwerk</code> gem can help with the mode to resolve all autoload at once.</p> Ruby master - Feature #17414 (Open): Ractor should allow access to shareable attributes for Modul...https://bugs.ruby-lang.org/issues/174142020-12-21T01:55:02Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Current situation is <em>very</em> limiting.</p>
<p>Use-case: global config.</p>
<p>Example: <a href="https://github.com/ruby/psych/blob/master/lib/psych.rb#L637-L640" class="external">yaml has a global config</a> and it's not clear to me how to make that Ractor-aware (nicely).</p>
<p>It is possible to have the same effect but in ugly ways:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># Using instance variables of Module not allowed:</span>
<span class="k">module</span> <span class="nn">Config</span>
<span class="k">class</span> <span class="o"><<</span> <span class="nb">self</span>
<span class="nb">attr_accessor</span> <span class="ss">:conf</span>
<span class="k">end</span>
<span class="nb">self</span><span class="p">.</span><span class="nf">conf</span> <span class="o">=</span> <span class="mi">42</span>
<span class="k">end</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="no">Config</span><span class="p">.</span><span class="nf">conf</span> <span class="o">=</span> <span class="mi">66</span> <span class="p">}.</span><span class="nf">take</span> <span class="c1"># => can not access instance variables from non-main Ractors</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="nb">puts</span> <span class="no">Config</span><span class="p">.</span><span class="nf">conf</span> <span class="p">}.</span><span class="nf">take</span> <span class="c1"># => can not access instance variables from non-main Ractors</span>
<span class="c1"># Same functionality using constants allowed:</span>
<span class="k">module</span> <span class="nn">Config</span>
<span class="k">class</span> <span class="o"><<</span> <span class="nb">self</span>
<span class="k">def</span> <span class="nf">conf</span>
<span class="no">CONF</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">conf</span><span class="o">=</span><span class="p">(</span><span class="n">new_conf</span><span class="p">)</span>
<span class="n">remove_const</span><span class="p">(</span><span class="ss">:CONF</span><span class="p">)</span>
<span class="nb">const_set</span><span class="p">(</span><span class="ss">:CONF</span><span class="p">,</span> <span class="n">new_conf</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="no">CONF</span> <span class="o">=</span> <span class="mi">42</span>
<span class="k">end</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="no">Config</span><span class="p">.</span><span class="nf">conf</span> <span class="o">=</span> <span class="mi">66</span> <span class="p">}.</span><span class="nf">take</span> <span class="c1"># => ok</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="nb">puts</span> <span class="no">Config</span><span class="p">.</span><span class="nf">conf</span> <span class="p">}.</span><span class="nf">take</span> <span class="c1"># => 66</span>
<span class="c1"># Same functionality using methods allowed:</span>
<span class="k">module</span> <span class="nn">Config</span>
<span class="k">class</span> <span class="o"><<</span> <span class="nb">self</span>
<span class="k">def</span> <span class="nf">conf</span>
<span class="mi">42</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">conf</span><span class="o">=</span><span class="p">(</span><span class="n">new_conf</span><span class="p">)</span>
<span class="n">singleton_class</span><span class="p">.</span><span class="nf">undef_method</span><span class="p">(</span><span class="ss">:conf</span><span class="p">)</span>
<span class="n">define_singleton_method</span><span class="p">(</span><span class="ss">:conf</span><span class="p">,</span> <span class="o">&</span><span class="no">Ractor</span><span class="p">.</span><span class="nf">make_shareable</span><span class="p">(</span><span class="no">Proc</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="n">new_conf</span> <span class="p">}))</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="no">Config</span><span class="p">.</span><span class="nf">conf</span> <span class="o">=</span> <span class="mi">66</span> <span class="p">}.</span><span class="nf">take</span> <span class="c1"># => ok</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="nb">puts</span> <span class="no">Config</span><span class="p">.</span><span class="nf">conf</span> <span class="p">}.</span><span class="nf">take</span> <span class="c1"># => 66</span>
</code></pre>
<p>The priority would be to allow reading these instance variables if they are shareable. Ideally writing would also be allowed, but limiting that to main ractor is less probablematic than with reading.</p> Ruby master - Feature #17404 (Open): Ractor `move:` API to allow shareability checkhttps://bugs.ruby-lang.org/issues/174042020-12-17T18:29:50Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I'd like to <code>ractor.send(message)</code> and express that <code>message</code> should be shareable. Currently I'm given two choices: <code>move: true</code> and <code>move: false</code> / nothing, neither of which have an effect if my <code>message</code> is shareable, and neither of which will tell me in case there's a bug in my program and <code>message</code> is not shareable.</p>
<p>Could we consider a slightly different API (for 3.0 or 3.1)?</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">ractor</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="ss">pass: :copy</span><span class="p">)</span> <span class="c1"># => like current `move: false`</span>
<span class="n">ractor</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="ss">pass: :move</span><span class="p">)</span> <span class="c1"># => like current `move: true`</span>
<span class="n">ractor</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="ss">pass: :share</span><span class="p">)</span> <span class="c1"># => raise in case message is not shareable</span>
<span class="n">ractor</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">message</span><span class="p">)</span> <span class="c1"># => same as `pass: :copy`</span>
</code></pre> Ruby master - Bug #17400 (Open): Incorrect character downcase for Greek Sigmahttps://bugs.ruby-lang.org/issues/174002020-12-16T23:47:34Zxfalcox (Rafael Silva)xfalcox@gmail.com
<p>An issue caused by this bug was first reported at Discourse support community at <a href="https://meta.discourse.org/t/unicode-username-results-in-error-loading-profile-page/173182?u=falco" class="external">https://meta.discourse.org/t/unicode-username-results-in-error-loading-profile-page/173182?u=falco</a>.</p>
<p>The issue is that in Greek, there are two ways to downcase the letter ‘Σ’</p>
<ul>
<li>‘ς’ when it is used at the end of a word</li>
<li>‘σ’ anywhere else</li>
</ul>
<p>NodeJS follows this rule:</p>
<pre><code>➜ node
Welcome to Node.js v12.11.1.
Type ".help" for more information.
> "ΣΠΥΡΟΣ".toLowerCase()
'σπυρος'
</code></pre>
<p>Python too:</p>
<pre><code>➜ python
Python 3.8.2 (default, Nov 23 2020, 16:33:30)
[GCC 10.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> "ΣΠΥΡΟΣ".lower()
'σπυρος'
</code></pre>
<p>Ruby (both 2.7 and 3) doesn't:</p>
<pre><code>➜ ruby --version
ruby 3.0.0dev (2020-12-16T18:46:44Z master 93ba3ac036) [x86_64-linux]
➜ irb
irb(main):001:0> "ΣΠΥΡΟΣ".downcase
=> "σπυροσ"
</code></pre>
<pre><code>➜ ruby --version
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]
➜ irb
irb(main):001:0> "ΣΠΥΡΟΣ".downcase
=> "σπυροσ"
</code></pre> Ruby master - Feature #17393 (Open): `Ractor::Moved#inspect`https://bugs.ruby-lang.org/issues/173932020-12-14T20:48:49Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>It could be helpful to define <code>Ractor::Moved#inspect</code> and output the source location of when the data was moved. If preferred, it could raise an error with this information:</p>
<pre><code>x = []
Ractor.new{ receive }.send(x, move: true)
p x # => "Data was moved in `example.rb:4`"
# or
p x # => "Data was moved in `example.rb:4`" (Ractor::MovedError)
</code></pre>
<p>Also <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/710">@zverok (Victor Shepelev)</a> and myself were wondering if there was a technical reason to freeze <code>Ractor::Moved</code>? If not, is it only to "force" people to use refinements (which are allowed on frozen classes)? It's already known that it is in general a bad idea to modify builtin classes, so it's not clear to me that freezing that class is best.</p> Ruby master - Bug #17359 (Open): Ractor copy mode is not Ractor-safehttps://bugs.ruby-lang.org/issues/173592020-12-01T08:29:37Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>It should not be possible to mutate an object across Ractors, but the copy mode allows it currently:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Foo</span>
<span class="nb">attr_accessor</span> <span class="ss">:x</span>
<span class="k">def</span> <span class="nf">initialize_copy</span><span class="p">(</span><span class="o">*</span><span class="p">)</span>
<span class="vg">$last</span> <span class="o">=</span> <span class="nb">self</span>
<span class="k">super</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">o</span> <span class="o">=</span> <span class="no">Foo</span><span class="p">.</span><span class="nf">new</span>
<span class="n">o</span><span class="p">.</span><span class="nf">x</span> <span class="o">=</span> <span class="mi">42</span>
<span class="n">r</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">o</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">copy</span><span class="o">|</span>
<span class="nb">puts</span> <span class="n">copy</span><span class="p">.</span><span class="nf">x</span> <span class="c1"># => 42</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">yield</span> <span class="ss">:sync</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">yield</span> <span class="ss">:sync</span>
<span class="nb">puts</span> <span class="n">copy</span><span class="p">.</span><span class="nf">x</span> <span class="c1"># => 666</span>
<span class="k">end</span>
<span class="n">r</span><span class="p">.</span><span class="nf">take</span> <span class="c1"># => :sync</span>
<span class="vg">$last</span><span class="p">.</span><span class="nf">x</span> <span class="o">=</span> <span class="mi">666</span>
<span class="n">r</span><span class="p">.</span><span class="nf">take</span> <span class="c1"># => :sync</span>
<span class="n">r</span><span class="p">.</span><span class="nf">take</span>
</code></pre>
<p>Maybe the <code>copy</code> object should be marked as moved?</p> Ruby master - Feature #17288 (Open): Optimize __send__ call with a literal method namehttps://bugs.ruby-lang.org/issues/172882020-10-27T08:32:40Zmrkn (Kenta Murata)muraken@gmail.com
<p>I made a patch to optimize a <code>__send__</code> call with a literal method name. This optimization replaces a <code>__send__</code> method call with a <code>send</code> instruction. The patch is available in <a href="https://github.com/ruby/ruby/pull/3707" class="external">this pull-request</a>.</p>
<p>By this change, the redefined <code>__send__</code> method is no longer called when it is called by a literal method name. I guess it is no problem because the following warning message is displayed for a long time.</p>
<pre><code>$ ruby -e 'def __send__; end'
-e:1: warning: redefining `__send__' may cause serious problems
</code></pre>
<p>This change makes the optimized case x5~x6 faster. The benchmark result is below:</p>
<pre><code>$ make benchmark COMPARE_RUBY="../../ruby/build-o3/ruby" ITEM=vm_send.yml
(snip)
# Iteration per second (i/s)
| |compare-ruby|built-ruby|
|:------------|-----------:|---------:|
|vm_send | 18.536M| 113.778M|
| | -| 6.14x|
|vm_send_var | 18.085M| 16.595M|
| | 1.09x| -|
</code></pre> Ruby master - Feature #17279 (Open): Allow a negative step in Range#step with a blockhttps://bugs.ruby-lang.org/issues/172792020-10-22T02:23:48Zmrkn (Kenta Murata)muraken@gmail.com
<p><code>Range#step</code> prohibits a negative step when a block is given.</p>
<pre><code>>> (6..3).step(-1) {|i| p i }
Traceback (most recent call last):
5: from /home/mrkn/.rbenv/versions/2.7/bin/irb:23:in `<main>'
4: from /home/mrkn/.rbenv/versions/2.7/bin/irb:23:in `load'
3: from /home/mrkn/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/irb-1.2.4/exe/irb:11:in `<top (required)>'
2: from (irb):1
1: from (irb):1:in `step'
ArgumentError (step can't be negative)
</code></pre>
<p>But <code>Range#step</code> allows a negative step when it is called without a block. In this case, <code>Range#step</code> creates an ArithmeticSequence, and <code>ArithmeticSequence#each</code> can iterate with a negative step.</p>
<pre><code>>> (6..3).step(-1).each {|i| p i }
6
5
4
3
=> ((6..3).step(-1))
</code></pre>
<p>I think the prohibition of a negative step in <code>Range#step</code> has already been meaningless, so it may be better to permit it for consistency.</p> Ruby master - Feature #17210 (Open): More readable and useful `Set#inspect`https://bugs.ruby-lang.org/issues/172102020-10-02T04:33:18Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I would like to change <code>Set#inspect</code>/<code>to_s</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># before</span>
<span class="nb">puts</span> <span class="no">Set</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">]</span> <span class="c1"># => "#<Set: {1, 2, 3}>"</span>
<span class="c1"># after</span>
<span class="nb">puts</span> <span class="no">Set</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">]</span> <span class="c1"># => "Set[1, 2, 3]"</span>
</code></pre>
<p>This output is shorter, readable, and has the property that it corresponds to Ruby code</p> Ruby master - Feature #17184 (Open): No stdlib function to perform simple string replacementhttps://bugs.ruby-lang.org/issues/171842020-09-24T11:37:04Zsheerun (Adam Stankiewicz)sheerun@sher.pl
<p>I have following simple <code>build.rb</code>:</p>
<pre><code class="rb syntaxhl" data-language="rb"><span class="n">template</span> <span class="o">=</span> <span class="no">File</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="s1">'template.vim'</span><span class="p">)</span>
<span class="n">script</span> <span class="o">=</span> <span class="no">File</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="s1">'script.vim'</span><span class="p">)</span>
<span class="no">File</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="s1">'app.vim'</span><span class="p">,</span> <span class="n">template</span><span class="p">.</span><span class="nf">gsub</span><span class="p">(</span><span class="s2">"SCRIPT"</span><span class="p">,</span> <span class="n">script</span><span class="p">))</span>
</code></pre>
<p>And then following <code>template.vim</code>:</p>
<pre><code class="vim syntaxhl" data-language="vim"><span class="c">" some header</span>
SCRIPT
</code></pre>
<p>Plus following <code>script.vim</code>:</p>
<pre><code class="vim syntaxhl" data-language="vim"><span class="k">if</span> <span class="nv">g:something</span> <span class="p">=~</span> <span class="s2">"\s\+"</span>
echo <span class="s1">'g:something is empty'</span>
<span class="k">endif</span>
</code></pre>
<p>I'd expect that the script above produces <code>app.vim</code> with following contents:</p>
<pre><code class="vim syntaxhl" data-language="vim"><span class="c">" some header</span>
<span class="k">if</span> <span class="nv">g:something</span> <span class="p">=~</span> <span class="s2">"\s\+"</span>
echo <span class="s1">'g:something is empty'</span>
<span class="k">endif</span>
</code></pre>
<p>Unfortunately it produces following:</p>
<pre><code class="vim syntaxhl" data-language="vim"><span class="c">" some header</span>
<span class="k">if</span> <span class="nv">g:something</span> <span class="p">=~</span> <span class="s2">"\s"</span>
echo <span class="s1">'g:something is empty'</span>
<span class="k">endif</span>
</code></pre>
<p>It's probably because gsub interprets <code>\+</code> in script as back-reference.</p>
<p>I tried to find replacement function in ruby that just replaces one string with something else, without interpreting replacement in any way, but surprisingly I haven't found any.. Am I mistaken?</p> Ruby master - Feature #17173 (Open): open-uri で ciphers を設定したいhttps://bugs.ruby-lang.org/issues/171732020-09-16T04:55:19Zznz (Kazuhiro NISHIYAMA)
<p>Debian GNU/Linux 10 (buster) の OpenSSL 1.1.1d の環境だと <a href="https://www.famitsu.com" class="external">https://www.famitsu.com</a> で <code>dh key too small</code> になってつながらないのですが、 <code>ciphers</code> に <code>DEFAULT:!DH</code> を設定するとつながるので、 <code>open-uri</code> 経由でも <code>ciphers</code> を設定したいです。</p>
<p>curl での確認:</p>
<pre><code>% curl --head https://www.famitsu.com/
curl: (35) error:141A318A:SSL routines:tls_process_ske_dhe:dh key too small
zsh: exit 35 curl --head https://www.famitsu.com/
% curl --ciphers 'DEFAULT:!DH' --head https://www.famitsu.com/
HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Wed, 16 Sep 2020 04:48:25 GMT
Content-Type: text/html
Connection: keep-alive
Vary: Accept-Encoding
Accept-Ranges: bytes
Vary: Accept-Encoding
Strict-Transport-Security: max-age=60
</code></pre>
<p>ruby での確認:</p>
<pre><code>% ruby -r open-uri -e 'open("https://www.famitsu.com/")'
Traceback (most recent call last):
13: from -e:1:in `<main>'
12: from /usr/lib/ruby/2.5.0/open-uri.rb:35:in `open'
11: from /usr/lib/ruby/2.5.0/open-uri.rb:735:in `open'
10: from /usr/lib/ruby/2.5.0/open-uri.rb:165:in `open_uri'
9: from /usr/lib/ruby/2.5.0/open-uri.rb:224:in `open_loop'
8: from /usr/lib/ruby/2.5.0/open-uri.rb:224:in `catch'
7: from /usr/lib/ruby/2.5.0/open-uri.rb:226:in `block in open_loop'
6: from /usr/lib/ruby/2.5.0/open-uri.rb:755:in `buffer_open'
5: from /usr/lib/ruby/2.5.0/open-uri.rb:337:in `open_http'
4: from /usr/lib/ruby/2.5.0/net/http.rb:909:in `start'
3: from /usr/lib/ruby/2.5.0/net/http.rb:920:in `do_start'
2: from /usr/lib/ruby/2.5.0/net/http.rb:985:in `connect'
1: from /usr/lib/ruby/2.5.0/net/protocol.rb:44:in `ssl_socket_connect'
/usr/lib/ruby/2.5.0/net/protocol.rb:44:in `connect_nonblock': SSL_connect returned=1 errno=0 state=error: dh key too small (OpenSSL::SSL::SSLError)
zsh: exit 1 ruby -r open-uri -e 'open("https://www.famitsu.com/")'
% ruby -r net/http -e 'http=Net::HTTP.new("www.famitsu.com", 443); http.use_ssl=true; http.ciphers="DEFAULT:!DH"; p http.get("/")'
#<Net::HTTPOK 200 OK readbody=true>
</code></pre>
<p><a href="https://www.ssllabs.com/ssltest/analyze.html?d=www.famitsu.com" class="external">https://www.ssllabs.com/ssltest/analyze.html?d=www.famitsu.com</a> によると Cipher Suites は</p>
<pre><code># TLS 1.2 (suites in server-preferred order)
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x9f) DH 1024 bits FS WEAK 256
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x9e) DH 1024 bits FS WEAK 128
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (0x6b) DH 1024 bits FS WEAK 256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (0x67) DH 1024 bits FS WEAK 128
TLS_RSA_WITH_AES_256_GCM_SHA384 (0x9d) WEAK 256
TLS_RSA_WITH_AES_128_GCM_SHA256 (0x9c) WEAK 128
TLS_RSA_WITH_AES_256_CBC_SHA256 (0x3d) WEAK 256
TLS_RSA_WITH_AES_128_CBC_SHA256 (0x3c) WEAK 128
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030) ECDH secp384r1 (eq. 7680 bits RSA) FS 256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f) ECDH secp384r1 (eq. 7680 bits RSA) FS 128
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028) ECDH secp384r1 (eq. 7680 bits RSA) FS WEAK 256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027) ECDH secp384r1 (eq. 7680 bits RSA) FS WEAK 128
</code></pre>
<p>となっていて、 Handshake Simulation では</p>
<pre><code>Chrome 80 / Win 10 R RSA 2048 (SHA256) TLS 1.2 TLS_RSA_WITH_AES_256_GCM_SHA384 No FS
Firefox 73 / Win 10 R RSA 2048 (SHA256) TLS 1.2 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ECDH secp256r1 FS
OpenSSL 1.1.1c R RSA 2048 (SHA256) TLS 1.2 TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 DH 1024 FS
</code></pre>
<p>のようになっていて、 <code>TLS_DHE_RSA_WITH_AES_256_GCM_SHA384</code> が選ばれて DH 1024 bit を拒否するクライアントからは繋らない設定になっているサーバーがあるようです。(<code>dh key too small</code> で web 検索すると同様の設定のサーバーは他にもあるようです。)</p> Ruby master - Misc #17154 (Open): Update Pathname Documentation to Clarify Expected Behaviorhttps://bugs.ruby-lang.org/issues/171542020-09-05T02:29:29Zresperat (Ralph Esperat)
<p>I would like to suggest adding a sentence to the documentation for <a href="https://ruby-doc.org/stdlib-2.7.1/libdoc/pathname/rdoc/Pathname.html" class="external">Pathname</a> to make clear the unusual behavior of <code>Pathname#+</code> when an absolute path is included in the arguments. In such a situation, <code>Pathname#+</code> drops the paths prior to the last absolute path which I understand to be the intended behavior, but it is not obviously intended, only showing up tangentially as an example in the documentation.</p>
<pre><code>p3 = p1 + "/etc/passwd" # Pathname:/etc/passwd
</code></pre>
<p>The Pathname documentation states that " <strong>All functionality</strong> from File, FileTest, and some from Dir and FileUtils is included, <strong>in an unsurprising way</strong> ..." and later when referring to core methods such as <code>Pathname#+</code> "These methods are <strong>effectively manipulating a String</strong> , because that's all a path is." However, similar uses of both <a href="https://ruby-doc.org/core-2.7.1/File.html" class="external">File</a> and <a href="https://ruby-doc.org/core-2.7.1/String.html" class="external">String</a> would produce the expected result of including all of the arguments:</p>
<pre><code>s1 = "/usr"
s2 = s1 + "/etc/passwd" # "/usr/etc/passwd"
f1 = File.new("/usr" + "/etc/passwd") # (No such file or directory @ rb_sysopen - /usr/etc/passwd)
</code></pre>
<p>A bug report was previously filed to "fix" this functionality (<a class="issue tracker-1 status-6 priority-4 priority-default closed" title="Status: Rejected" href="https://bugs.ruby-lang.org/issues/15564">Bug #15564: Pathname#+(pathpart) returns pathpart when pathpart is absolute</a>), not understanding it to be intentional. Other common help websites such as <a href="https://stackoverflow.com/questions/12464361/concatenating-absolute-paths-with-the-pathname-class" class="external">Stack Overflow</a> also show users who do not expect this behavior from this method. Adding a statement to the documentation for the <a href="https://ruby-doc.org/stdlib-2.7.1/libdoc/pathname/rdoc/Pathname.html#method-i-2B" class="external">Pathname#+</a> method will make it clear to users exactly what to expect and that this is the intended behavior. I would suggest simply the following, the first sentence of which is already present:</p>
<p><code>Appends a pathname fragment to self to produce a new Pathname object. If an absolute path is provided as any of the arguments, discards all arguments prior to the last absolute path provided.</code></p>
<p>I appreciate your consideration of this request.</p>
<p>ruby -v: ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]</p> Ruby master - Feature #16992 (Open): Sets: officially orderedhttps://bugs.ruby-lang.org/issues/169922020-06-26T20:30:50Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Officially, set elements have uncertain order. This predades when Hash started being ordered (Ruby 1.9.0, Xmas 2007). Sets have since been de-facto insertion-ordered. FYI, in those 13 years, there have been about 70 commits to <code>lib/set.rb</code>.</p>
<p>I have the impression that a non-negligible amount of code in the wild rely on sets being ordered, at least under most circumstances. I feel that this should be officialized.</p>
<p>If sets are truly unordered, then why do we hesitate to make an optimization of <code>&</code> and <code>|</code>: <a href="https://bugs.ruby-lang.org/issues/15281" class="external">https://bugs.ruby-lang.org/issues/15281</a></p>
<p>See also: <a href="https://bugs.ruby-lang.org/issues/14069" class="external">https://bugs.ruby-lang.org/issues/14069</a></p> Ruby master - Feature #16989 (Open): Sets: need ♥️https://bugs.ruby-lang.org/issues/169892020-06-26T20:18:17Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I am opening a series of feature requests on <code>Set</code>, all of them based on this usecase.</p>
<p>The main usecase I have in mind is my recent experience with <code>RuboCop</code>. I noticed a big number of frozen arrays being used only to later call <code>include?</code> on them. This is <code>O(n)</code> instead of <code>O(1)</code>.</p>
<p>Trying to convert them to <code>Set</code>s causes major compatibility issues, as well as very frustrating situations and some cases that would make them much less efficient.</p>
<p>Because of these incompatibilities, <code>RuboCop</code> is in the process of using a custom class based on <code>Array</code> with optimized <code>include?</code> and <code>===</code>. <code>RuboCop</code> runs multiple checks on Ruby code. Those checks are called cops. <code>RuboCop</code> performance is (IMO) pretty bad and some cops currently are in <code>O(n^2)</code> where n is the size of the code being inspected. Even given these extremely inefficient cops, optimizing the 100+ such arrays (most of which are quite small btw) gave a 5% speed boost.</p>
<p>RuboCop PRs for reference: <a href="https://github.com/rubocop-hq/rubocop-ast/pull/29" class="external">https://github.com/rubocop-hq/rubocop-ast/pull/29</a><br>
<a href="https://github.com/rubocop-hq/rubocop/pull/8133" class="external">https://github.com/rubocop-hq/rubocop/pull/8133</a></p>
<p>My experience tells me that there are many other opportunities to use <code>Set</code>s that are missed because <code>Set</code>s are not builtin, not known enough and have no shorthand notation.</p>
<p>In this issue I'd like to concentrate the discussion on the following request: <code>Set</code>s should be core objects, in the same way that <code>Complex</code> were not and are now. Some of the upcoming feature requests would be easier (or only possible) to implement were <code>Set</code>s builtin.</p> Ruby master - Feature #16986 (Open): Anonymous Struct literalhttps://bugs.ruby-lang.org/issues/169862020-06-26T06:58:53Zko1 (Koichi Sasada)
<a name="Abstract"></a>
<h1 >Abstract<a href="#Abstract" class="wiki-anchor">¶</a></h1>
<p>How about introducing anonymous Struct literal such as <code>${a: 1, b: 2}</code>?<br>
It is almost the same as <code>Struct.new(:a, :b).new(1, 2)</code>.</p>
<a name="Proposal"></a>
<h1 >Proposal<a href="#Proposal" class="wiki-anchor">¶</a></h1>
<a name="Background"></a>
<h2 >Background<a href="#Background" class="wiki-anchor">¶</a></h2>
<p>In many cases, people use hash objects to represent a set of values such as <code>person = {name: "ko1", country: 'Japan'}</code> and access its values through <code>person[:name]</code> and so on. It is not easy to write (three characters <code>[:]</code>!), and it easily introduces misspelling (<code>person[:nama]</code> doesn't raise an error).</p>
<p>If we make a <code>Struct</code> object by doing <code>Person = Struct.new(:name, :age)</code> and <code>person = Person.new('ko1', 'Japan')</code>, we can access its values through <code>person.name</code> naturally. However, it costs coding. And in some cases, we don't want to name the class (such as <code>Person</code>).</p>
<p>Using <code>OpenStruct</code> (<code>person = OpenStruct.new(name: "ko1", country: "Japan")</code>), we can access it through <code>person.name</code>, but we can extend the fields unintentionally, and the performance is not good.</p>
<p>Of course, we can define a class <code>Person</code> with attr_readers. But it takes several lines.</p>
<p>To summarize the needs:</p>
<ul>
<li>Easy to write
<ul>
<li>Doesn't require declaring the class</li>
<li>Accessible through <code>person.name</code> format</li>
</ul>
</li>
<li>Limited fields</li>
<li>Better performance</li>
</ul>
<a name="Idea"></a>
<h2 >Idea<a href="#Idea" class="wiki-anchor">¶</a></h2>
<p>Introduce new literal syntax for an anonymous Struct such as: <code>${ a: 1, b: 2 }</code>.<br>
Similar to Hash syntax (with labels), but with <code>$</code> prefix to distinguish.</p>
<p>Anonymous structs which have the same member in the same order share their class.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="n">s1</span> <span class="o">=</span> <span class="err">$</span><span class="p">{</span><span class="ss">a: </span><span class="mi">1</span><span class="p">,</span> <span class="ss">b: </span><span class="mi">2</span><span class="p">,</span> <span class="ss">c: </span><span class="mi">3</span><span class="p">}</span>
<span class="n">s2</span> <span class="o">=</span> <span class="err">$</span><span class="p">{</span><span class="ss">a: </span><span class="mi">1</span><span class="p">,</span> <span class="ss">b: </span><span class="mi">2</span><span class="p">,</span> <span class="ss">c: </span><span class="mi">3</span><span class="p">}</span>
<span class="n">assert</span> <span class="n">s1</span> <span class="o">==</span> <span class="n">s2</span>
<span class="n">s3</span> <span class="o">=</span> <span class="err">$</span><span class="p">{</span><span class="ss">a: </span><span class="mi">1</span><span class="p">,</span> <span class="ss">c: </span><span class="mi">3</span><span class="p">,</span> <span class="ss">b: </span><span class="mi">2</span><span class="p">}</span>
<span class="n">s4</span> <span class="o">=</span> <span class="err">$</span><span class="p">{</span><span class="ss">d: </span><span class="mi">4</span><span class="p">}</span>
<span class="n">assert_equal</span> <span class="kp">false</span><span class="p">,</span> <span class="n">s1</span> <span class="o">==</span> <span class="n">s3</span>
<span class="n">assert_equal</span> <span class="kp">false</span><span class="p">,</span> <span class="n">s1</span> <span class="o">==</span> <span class="n">s4</span>
</code></pre>
<a name="Note"></a>
<h2 >Note<a href="#Note" class="wiki-anchor">¶</a></h2>
<p>Unlike Hash literal syntax, this proposal only allows <code>label: expr</code> notation. No <code>${**h}</code> syntax.<br>
This is because if we allow to splat a Hash, it can be a vulnerability by splatting outer-input Hash.</p>
<p>Thanks to this spec, we can specify anonymous Struct classes at compile time.<br>
We don't need to find or create Struct classes at runtime.</p>
<a name="Implementatation"></a>
<h2 >Implementatation<a href="#Implementatation" class="wiki-anchor">¶</a></h2>
<p><a href="https://github.com/ruby/ruby/pull/3259" class="external">https://github.com/ruby/ruby/pull/3259</a></p>
<a name="Discussion"></a>
<h1 >Discussion<a href="#Discussion" class="wiki-anchor">¶</a></h1>
<a name="Notation"></a>
<h2 >Notation<a href="#Notation" class="wiki-anchor">¶</a></h2>
<p>Matz said he thought about <code>{|a: 1, b: 2 |}</code> syntax.</p>
<a name="Performance"></a>
<h2 >Performance<a href="#Performance" class="wiki-anchor">¶</a></h2>
<p>Surprisingly, Hash is fast and Struct is slow.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Benchmark</span><span class="p">.</span><span class="nf">driver</span> <span class="k">do</span> <span class="o">|</span><span class="n">r</span><span class="o">|</span>
<span class="n">r</span><span class="p">.</span><span class="nf">prelude</span> <span class="o"><<~</span><span class="no">PRELUDE</span><span class="sh">
st = Struct.new(:a, :b).new(1, 2)
hs = {a: 1, b: 2}
class C
attr_reader :a, :b
def initialize() = (@a = 1; @b = 2)
end
ob = C.new
</span><span class="no"> PRELUDE</span>
<span class="n">r</span><span class="p">.</span><span class="nf">report</span> <span class="s2">"ob.a"</span>
<span class="n">r</span><span class="p">.</span><span class="nf">report</span> <span class="s2">"hs[:a]"</span>
<span class="n">r</span><span class="p">.</span><span class="nf">report</span> <span class="s2">"st.a"</span>
<span class="k">end</span>
<span class="cp">__END__
Warming up --------------------------------------
ob.a 38.100M i/s - 38.142M times in 1.001101s (26.25ns/i, 76clocks/i)
hs[:a] 37.845M i/s - 38.037M times in 1.005051s (26.42ns/i, 76clocks/i)
st.a 33.348M i/s - 33.612M times in 1.007904s (29.99ns/i, 87clocks/i)
Calculating -------------------------------------
ob.a 87.917M i/s - 114.300M times in 1.300085s (11.37ns/i, 33clocks/i)
hs[:a] 85.504M i/s - 113.536M times in 1.327850s (11.70ns/i, 33clocks/i)
st.a 61.337M i/s - 100.045M times in 1.631064s (16.30ns/i, 47clocks/i)
Comparison:
ob.a: 87917391.4 i/s
hs[:a]: 85503703.6 i/s - 1.03x slower
st.a: 61337463.3 i/s - 1.43x slower
</span></code></pre>
<p>I believe we can speed up <code>Struct</code> similarly to ivar accesses, so we can improve the performance.</p>
<p>BTW, OpenStruct (os.a) is slow.</p>
<pre><code>Comparison:
hs[:a]: 92835317.7 i/s
ob.a: 85865849.5 i/s - 1.08x slower
st.a: 53480417.5 i/s - 1.74x slower
os.a: 12541267.7 i/s - 7.40x slower
</code></pre>
<p>For memory consumption, <code>Struct</code> is more lightweight because we don't need to keep the key names.</p>
<a name="Naming"></a>
<h2 >Naming<a href="#Naming" class="wiki-anchor">¶</a></h2>
<p>If we name an anonymous class, literals with the same members share the name.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">s1</span> <span class="o">=</span> <span class="err">$</span><span class="p">{</span><span class="n">a</span><span class="p">:</span><span class="mi">1</span><span class="p">}</span>
<span class="n">s2</span> <span class="o">=</span> <span class="err">$</span><span class="p">{</span><span class="n">a</span><span class="p">:</span><span class="mi">2</span><span class="p">}</span>
<span class="nb">p</span> <span class="p">[</span><span class="n">s1</span><span class="p">,</span> <span class="n">s2</span><span class="p">]</span> <span class="c1">#=> [#<struct a=1>, #<struct a=2>]</span>
<span class="no">A</span> <span class="o">=</span> <span class="n">s1</span><span class="p">.</span><span class="nf">class</span>
<span class="nb">p</span> <span class="p">[</span><span class="n">s1</span><span class="p">,</span> <span class="n">s2</span><span class="p">]</span> <span class="c1">#=> [#<struct A a=1>, #<struct A a=2>]</span>
</code></pre>
<p>Maybe that is not a good behavior.</p> Ruby master - Feature #16985 (Open): Improve `pp` for `Hash` and `String`https://bugs.ruby-lang.org/issues/169852020-06-25T17:28:06Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Could we improve <code>pp</code> for <code>Hash</code> and <code>String</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">pp</span><span class="p">({</span><span class="ss">hello: </span><span class="s1">'My name is "Marc-André"'</span><span class="p">})</span>
<span class="c1"># =></span>
<span class="p">{</span><span class="ss">hello: </span><span class="s1">'My name is "Marc-André"'</span><span class="p">}</span>
<span class="c1"># instead of</span>
<span class="p">{</span><span class="ss">:hello</span><span class="o">=></span><span class="s2">"My name is </span><span class="se">\"</span><span class="s2">Marc-André</span><span class="se">\"</span><span class="s2">"</span><span class="p">}</span>
</code></pre>
<p>If any key is non-symbol, they would continue to be output as <code><key> => <value></code>. If a string contains single quotes, or characters that need escaping (e.g. <code>"\n"</code>), current format would be used.</p>
<p>I'll gladly provide a PR if this is deemed acceptable.</p>
<p>I would even like this for <code>String#inspect</code> and <code>Hash#inspect</code> but it's not clear if this could lead to much incompatibility (maybe test suites?)</p> Ruby master - Feature #16894 (Open): Integer division for Ruby 3https://bugs.ruby-lang.org/issues/168942020-05-15T03:20:39Zankane (Andrew Kane)
<p>Hi Ruby team,</p>
<p>It'd be great if division in Ruby matched what we all learned in school.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="mi">1</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">==</span> <span class="mf">0.5</span>
</code></pre>
<p>New developers wouldn't immediately be confused when they try to do division and experienced developers could stop adding to_f to their code (typically after they get tripped up on the first run). In my experience, floating point division is way more common than floor division. This could definitely break existing code, so I understand it's a decision that shouldn't be made lightly. Overall, Ruby is really intuitive, but this is one place where it's not.</p>
<p>It looks like this was considered for Ruby 2.0 as well as few years ago in <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Integer#/ の改訂 (Rejected)" href="https://bugs.ruby-lang.org/issues/5512">#5512</a>, so feel free to close if it's not something you'd like to reconsider right now.</p> Ruby master - Feature #16833 (Open): Add Enumerable#empty?https://bugs.ruby-lang.org/issues/168332020-05-06T14:09:02Zf3ndot (Justin Bull)
<p>It was surprising to me that Enumerator, something mixed into Array, does not include <code>#empty?</code>. I think it is reasonable to assume people may have to guard iterating and other logic based on the emptiness of an enumerator, such was my case.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="c1"># pretend there's convoluted enumerator logic to produce this structure</span>
<span class="n">table_rows</span> <span class="o">=</span> <span class="p">[{</span> <span class="ss">data: </span><span class="p">[</span><span class="s1">'First'</span><span class="p">,</span> <span class="s1">'Second'</span><span class="p">,</span> <span class="s1">'Third'</span><span class="p">],</span> <span class="ss">config: </span><span class="p">{}</span> <span class="p">},</span> <span class="p">{</span> <span class="ss">data: </span><span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">],</span> <span class="ss">config: </span><span class="p">{</span> <span class="ss">color: </span><span class="s1">'red'</span> <span class="p">}</span> <span class="p">}].</span><span class="nf">to_enum</span>
<span class="k">return</span> <span class="k">if</span> <span class="n">table_rows</span><span class="p">.</span><span class="nf">empty?</span>
<span class="n">table_header</span> <span class="o">=</span> <span class="n">table_rows</span><span class="p">.</span><span class="nf">first</span><span class="p">[</span><span class="ss">:data</span><span class="p">]</span> <span class="c1"># requires an empty guard</span>
<span class="c1"># ...</span>
</code></pre>
<p>I propose that it simply behaves as <code>#take(1).to_a.empty?</code> instead of aliasing to something like <code>#none?</code> because of falsey elements or <code>#size == 0</code> because of potential <code>nil</code> returns:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">[].</span><span class="nf">to_enum</span><span class="p">.</span><span class="nf">empty?</span> <span class="c1"># => true</span>
<span class="p">[</span><span class="kp">false</span><span class="p">].</span><span class="nf">to_enum</span><span class="p">.</span><span class="nf">empty?</span> <span class="c1"># => false</span>
<span class="p">[</span><span class="kp">nil</span><span class="p">].</span><span class="nf">to_enum</span><span class="p">.</span><span class="nf">empty?</span> <span class="c1"># => false</span>
<span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nf">to_enum</span><span class="p">.</span><span class="nf">empty?</span> <span class="c1"># => false</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">].</span><span class="nf">to_enum</span><span class="p">.</span><span class="nf">empty?</span> <span class="c1"># => false</span>
</code></pre> Ruby master - Misc #16188 (Open): What are the performance implications of the new keyword argume...https://bugs.ruby-lang.org/issues/161882019-09-29T18:27:43ZEregon (Benoit Daloze)
<p>In <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: "Real" keyword argument (Closed)" href="https://bugs.ruby-lang.org/issues/14183">#14183</a>, keyword arguments became further separated from positional arguments.</p>
<p>Contrary to the original design though, keyword and positional arguments are not fully separated for methods not accepting keyword arguments.<br>
Example: <code>foo(key: :value)</code> will <code>def foo(hash)</code> will pass a positional argument.<br>
This is of course better for compatibility, but I wonder what are the performance implications.</p>
<p>The block argument is completely separate in all versions, so no need to concern ourselves about that.</p>
<p>In Ruby <= 2.6:</p>
<ul>
<li>The caller never needs to know about the callee's arguments, it can just take all arguments and pass them as an array.<br>
The last argument might be used to extract keyword, but this is all done at the callee side.</li>
<li>Splitting kwargs composed of Symbol and non-Symbol keys can be fairly expensive, but it is a rare occurrence.<br>
If inlining the callee and kwargs are all passed as a literal Hash at the call site, there shouldn't be any overhead compared to positional arguments once JIT'ed.</li>
</ul>
<p>In Ruby 2.7:</p>
<ul>
<li>The caller needs to pass positional and keyword arguments separately, at least when calling a method accepting kwargs.<br>
But, if it calls a methods not accepting kwargs, then the "kwargs" (e.g. <code>foo(key: :value)</code>) should be treated just like a final Hash positional argument.</li>
<li>(If we had complete separation, then we could always pass positional and keyword arguments separately, so the caller could once again ignore the callee)</li>
</ul>
<p>How is the logic implemented in MRI for 2.7?</p>
<p>Specializing the caller for a given callee is a well-known technique.<br>
However, it becomes more difficult if different methods are called from the same callsite (polymorphic call), especially if one accepts kwargs and another does not.<br>
In that case, I think we will see a performance cost to this approach, by having to pass arguments differently based on the method to be called.</p>
<p>What about delegation using <code>ruby2_keywords</code>?<br>
Which checks does that add (compared to 2.6) in the merged approach with the Hash flag?</p> Ruby master - Feature #15991 (Open): Allow questionmarks in variable nameshttps://bugs.ruby-lang.org/issues/159912019-07-08T09:18:43Zaquaj (Jérémie Bonal)
<p>Hi,</p>
<p>I thought such an issue would've already been discussed but no number of searches allowed me to find a similar request. Feel free to close if I missed a previous refusal.</p>
<p>From time to time, especially when trying to clear up complex conditional logic, I find myself wishing I could add <code>?</code> to variable names, since I got used to it while naming methods.</p>
<p>For example, currently:</p>
<pre><code>if (node? && terminal?) || (halting && (value == halting))
# ...
end
</code></pre>
<p>becomes</p>
<pre><code>last_node = self.node? && self.terminal?
halt_on_node = halting && (value == halting)
if last_node || halt_on_node
# ...
end
</code></pre>
<p><code>halt_on_node</code> is clear enough, but <code>last_node</code> feels like it would contain a node, instead of expressing its actual purpose ("is the node the last one?").<br>
Right now a developer would have two options as I see them:<br>
1 - extract the conditional to a method <code>def last_node?</code> which can be a bit much if it's the only place this code is called.<br>
2 - rename the variable something like <code>is_last_node</code>, which feels a bit silly since we're in ruby and used to seeing <code>?</code>s for predicates.</p>
<p>Trying to assign to a questionmarked variable (<code>a? = true</code>) raises a <code>SyntaxError</code>. IMHO, it would make for more coherent design to allow it, just like we do in method names.</p>
<p>I was afraid that <code>variable?</code> would be already parsed as beginning a ternary expression (<code>variable?1:3</code>) but this isn't parsed either, the only thing it's used for is for method calls (<code>a?5 <==> a?(5)</code>), so this change wouldn't disrupt any current behavior, the expression would just be looked up like any other call instead of only looking up methods.</p>
<p>The only thing I can see with this is that it might raise the issue of allowing <code>!</code>s in variable names too, which I'm not sure makes a lot of sense (unlike <code>?</code> which denotes "booleanness", a trait shared by variables and methods alike, I can't see how a variable would be "dangerous").</p> Ruby master - Feature #15918 (Open): Pattern matching for Sethttps://bugs.ruby-lang.org/issues/159182019-06-12T13:44:57Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently, <code>Set</code> does not respond to <code>deconstruct</code>. Shouldn't we implement it using <code>to_a</code>?</p>
<pre><code>require 'set'
case Set[1, 2, 3]
in [1, 2, 3]
p "match"
else
p "no match"
end
# => "no match", should be "match"
</code></pre> Ruby master - Feature #15881 (Open): Optimize deconstruct in pattern matchinghttps://bugs.ruby-lang.org/issues/158812019-05-27T16:19:35Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">A</span>
<span class="k">def</span> <span class="nf">deconstruct</span>
<span class="nb">puts</span> <span class="s1">'deconstruct called'</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">case</span> <span class="no">A</span><span class="p">.</span><span class="nf">new</span>
<span class="k">in</span> <span class="p">[</span><span class="mi">2</span><span class="p">]</span>
<span class="mi">2</span>
<span class="k">in</span> <span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="mi">1</span>
<span class="k">else</span>
<span class="k">end</span>
</code></pre>
<p>Currently this outputs:</p>
<pre><code>deconstruct called
deconstruct called
=> 1
</code></pre>
<p>Shouldn't <code>deconstruct called</code> print only once, whenever the first deconstruction needed occurs?</p> Ruby master - Feature #15854 (Open): Tracing instance variable assignmenthttps://bugs.ruby-lang.org/issues/158542019-05-16T06:34:55Zigaiga (Kuniaki Igarashi)igaiga@gmail.com
<p>I suggest a feature "tracing instance variable assignment". It's useful for debugging.</p>
<p>Use case:</p>
<p>In Rails, we use instance variables in views and controllers. When we got a bug caused by instance variable unintentional values, if we traced instance variable assignment timing, it would be good informations.</p>
<p>And in Rails views, there are no source codes of self class. That's built dynamically.</p>
<p>Current behavior (Ruby2.6):</p>
<p>In Ruby 2.6, only if there is a source code file to assign instance variable, we can trace instance variable assignment by following code (check_instance_variable_assignment.rb). But it's difficult if the assignment codes are defined dynamically. For example, in Rails view.</p>
<p>(And in another story, global variables assignment are traced by Kernel#trace_var.)</p>
<p>check_instance_variable_assignment.rb</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">trace_start</span>
<span class="no">TracePoint</span><span class="p">.</span><span class="nf">trace</span><span class="p">(</span><span class="ss">:line</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">tp</span><span class="o">|</span>
<span class="n">target_class_name</span> <span class="o">=</span> <span class="s2">"Foo"</span>
<span class="n">target_instance_variable_name</span> <span class="o">=</span> <span class="s2">"@bar"</span>
<span class="n">line</span> <span class="o">=</span> <span class="no">File</span><span class="p">.</span><span class="nf">open</span><span class="p">(</span><span class="n">tp</span><span class="p">.</span><span class="nf">path</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">){</span><span class="o">|</span><span class="n">f</span><span class="o">|</span> <span class="n">f</span><span class="p">.</span><span class="nf">readlines</span><span class="p">[</span><span class="n">tp</span><span class="p">.</span><span class="nf">lineno</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="p">}</span>
<span class="n">node</span> <span class="o">=</span> <span class="no">RubyVM</span><span class="o">::</span><span class="no">AbstractSyntaxTree</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="n">line</span><span class="p">).</span><span class="nf">children</span><span class="p">.</span><span class="nf">last</span>
<span class="c1"># check instance variable assignment</span>
<span class="k">next</span> <span class="k">unless</span> <span class="n">node</span><span class="p">.</span><span class="nf">type</span> <span class="o">==</span> <span class="ss">:IASGN</span>
<span class="c1"># check class name</span>
<span class="n">target_class</span> <span class="o">=</span> <span class="no">Kernel</span><span class="p">.</span><span class="nf">const_get</span><span class="p">(</span><span class="n">target_class_name</span><span class="p">)</span>
<span class="k">next</span> <span class="k">unless</span> <span class="n">tp</span><span class="p">.</span><span class="nf">self</span><span class="p">.</span><span class="nf">is_a?</span><span class="p">(</span><span class="n">target_class</span><span class="p">)</span>
<span class="c1"># check variable name</span>
<span class="n">instance_variable_name</span> <span class="o">=</span> <span class="n">node</span><span class="p">.</span><span class="nf">children</span><span class="p">.</span><span class="nf">first</span>
<span class="k">next</span> <span class="k">unless</span> <span class="n">instance_variable_name</span> <span class="o">==</span> <span class="n">target_instance_variable_name</span><span class="p">.</span><span class="nf">to_sym</span>
<span class="nb">puts</span> <span class="s2">"</span><span class="si">#{</span><span class="n">target_class_name</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">target_instance_variable_name</span><span class="si">}</span><span class="s2"> is assigned in </span><span class="si">#{</span><span class="n">tp</span><span class="p">.</span><span class="nf">path</span><span class="si">}</span><span class="s2">:</span><span class="si">#{</span><span class="n">tp</span><span class="p">.</span><span class="nf">lineno</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">tp</span><span class="p">.</span><span class="nf">defined_class</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">tp</span><span class="p">.</span><span class="nf">method_id</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">Foo</span>
<span class="k">def</span> <span class="nf">bar</span>
<span class="vi">@bar</span> <span class="o">=</span> <span class="s2">"text"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">trace_start</span>
<span class="no">Foo</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">bar</span>
<span class="c1">#=> Foo @bar is assigned in check_instance_variable_assignment.rb:25 Foo bar</span>
</code></pre>
<p>Suggesting feature example:</p>
<p>Add new arguments for TracePoint.new method like :line and :call to trace instance variables assignment.</p>
<ul>
<li>:iasgn (IASGN name from RubyVM::AbstractSyntaxTree::Node)</li>
<li>:casgn (CVASGN (or CASGN?) name from RubyVM::AbstractSyntaxTree::Node. I think class variables tracing is useful too.)</li>
</ul>
<p>And get informations</p>
<ul>
<li>class name (It might be get by trace_point.self)</li>
<li>variable name ("@foo", "@@foo")</li>
</ul>
<p>A sample code to use the feature:</p>
<p>tp_iasgn.rb</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">TracePoint</span><span class="p">.</span><span class="nf">trace</span><span class="p">(</span><span class="ss">:iasgn</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">tp</span><span class="o">|</span>
<span class="n">target_class_name</span> <span class="o">=</span> <span class="s2">"Foo"</span>
<span class="n">target_instance_variable_name</span> <span class="o">=</span> <span class="s2">"@bar"</span>
<span class="c1"># check class name</span>
<span class="n">target_class</span> <span class="o">=</span> <span class="no">Kernel</span><span class="p">.</span><span class="nf">const_get</span><span class="p">(</span><span class="n">target_class_name</span><span class="p">)</span>
<span class="k">next</span> <span class="k">unless</span> <span class="n">tp</span><span class="p">.</span><span class="nf">self</span><span class="p">.</span><span class="nf">is_a?</span><span class="p">(</span><span class="n">target_class</span><span class="p">)</span>
<span class="c1"># check variable name</span>
<span class="k">next</span> <span class="k">unless</span> <span class="n">target_instance_variable_name</span> <span class="o">==</span> <span class="n">tp</span><span class="p">.</span><span class="nf">variable_name</span>
<span class="nb">puts</span> <span class="s2">"</span><span class="si">#{</span><span class="n">target_class_name</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">target_instance_variable_name</span><span class="si">}</span><span class="s2"> is assigned in </span><span class="si">#{</span><span class="n">tp</span><span class="p">.</span><span class="nf">path</span><span class="si">}</span><span class="s2">:</span><span class="si">#{</span><span class="n">tp</span><span class="p">.</span><span class="nf">lineno</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">tp</span><span class="p">.</span><span class="nf">method_id</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">tp</span><span class="p">.</span><span class="nf">defined_class</span><span class="si">}</span><span class="s2">"</span>
<span class="nb">puts</span> <span class="nb">caller</span> <span class="c1"># even in dynamic code case, we can get caller informations.</span>
<span class="k">end</span>
</code></pre> Ruby master - Feature #15837 (Open): Module#name_componentshttps://bugs.ruby-lang.org/issues/158372019-05-08T03:49:38Zmrkn (Kenta Murata)muraken@gmail.com
<p>I sometimes wrote the expression like below to extract the components of class path:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">klass</span><span class="p">.</span><span class="nf">name</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="s1">'::'</span><span class="p">).</span><span class="nf">last</span>
</code></pre>
<p>Similar expressions can be found in ruby-trunk:</p>
<pre><code>mrkn@mrkn-devel:~/src/github.com/ruby/ruby$ git grep split..::
ext/json/lib/json/common.rb: path.to_s.split(/::/).inject(Object) do |p, c|
ext/openssl/lib/openssl/config.rb: refsec, ref = ref.split('::', 2)
ext/psych/lib/psych/visitors/yaml_tree.rb: method = "visit_#{(klass.name || '').split('::').join('_')}"
lib/bundler/cli/gem.rb: constant_array = constant_name.split("::")
lib/bundler/vendor/molinillo/lib/molinillo/errors.rb: solver_name = opts.delete(:solver_name) { self.class.name.split('::').first }
lib/bundler/vendor/thor/lib/thor/parser/argument.rb: class_name = self.class.name.split("::").last
lib/bundler/vendor/thor/lib/thor/parser/arguments.rb: class_name = self.class.name.split("::").last.downcase
lib/optparse/version.rb: pkg = pkg.split(/::|\//).inject(::Object) {|m, c| m.const_get(c)}
lib/optparse/version.rb: path.split(/::|\//).inject(base) do |klass, name|
lib/rdoc/any_method.rb: name = @full_name.split('::')
lib/rdoc/context.rb: names = ename.split('::')
lib/rdoc/context.rb: path = [prefix] + path.split('::')
lib/rdoc/method_attr.rb: $1.split('::').last. # ClassName => class_name
lib/rdoc/parser/c.rb: ([\w\. \t]+ = \s+)?rb_define_(class|module)_under[\t\w, (]*?"(#{class_name.split('::').last})"%xm then
lib/rdoc/parser/ruby.rb: obj = name_t[:text].split("::").inject(Object) do |state, item|
lib/rdoc/store.rb: name = klass_name.split('::').last
lib/rdoc/store.rb: File.join @path, *klass_name.split('::')
lib/rdoc/store.rb: method_name = method_name.split('::').last
lib/rss/atom.rb: "#{self.class.name.split(/::/).last.downcase}="
lib/rss/atom.rb: target.__send__(self.class.name.split(/::/).last.downcase) {|x| x}
lib/rss/atom.rb: target.__send__("new_#{self.class.name.split(/::/).last.downcase}")
lib/rss/rss.rb: tag_name = klass.name.split(/::/).last
spec/bundler/support/artifice/fail.rb: const = name.split("::").reduce(Object) {|mod, sym| mod.const_get(sym) }
spec/mspec/lib/mspec/utils/name_map.rb: c.split('::').inject(base) do |dir, name|
spec/mspec/lib/mspec/utils/name_map.rb: name = mapping[c.split('::').last] || mapping.fetch(:default)
</code></pre>
<p>I think we need <code>Module#name_components</code> method that returns the array of symbols (or string, I prefer symbols) which comes from splitting name by <code>::</code>.</p> Ruby master - Feature #15815 (Open): Add option to raise NoMethodError for OpenStructhttps://bugs.ruby-lang.org/issues/158152019-05-01T13:52:20Zmtsmfm (Fumiaki Matsushima)mtsmfm@gmail.com
<p>GitHub PR: <a href="https://github.com/ruby/ruby/pull/2164" class="external">https://github.com/ruby/ruby/pull/2164</a></p>
<p>Currently, <code>OpenStruct#method_missing</code> returns <code>nil</code> even if the key isn't registered.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s1">'ostruct'</span>
<span class="n">os</span> <span class="o">=</span> <span class="no">OpenStruct</span><span class="p">.</span><span class="nf">new</span><span class="p">({</span><span class="ss">a: </span><span class="mi">1</span><span class="p">})</span>
<span class="n">os</span><span class="p">.</span><span class="nf">a</span> <span class="c1">#=> 1</span>
<span class="n">os</span><span class="p">.</span><span class="nf">b</span> <span class="c1">#=> nil</span>
</code></pre>
<p>I'd like to add <code>exception</code> option to raise <code>NoMethodError</code> in such case.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s1">'ostruct'</span>
<span class="n">os</span> <span class="o">=</span> <span class="no">OpenStruct</span><span class="p">.</span><span class="nf">new</span><span class="p">({</span><span class="ss">a: </span><span class="mi">1</span><span class="p">},</span> <span class="ss">exception: </span><span class="kp">true</span><span class="p">)</span>
<span class="n">os</span><span class="p">.</span><span class="nf">a</span> <span class="c1">#=> 1</span>
<span class="n">os</span><span class="p">.</span><span class="nf">b</span> <span class="c1">#=> NoMethodError</span>
</code></pre>
<a name="Use-case"></a>
<h2 >Use case<a href="#Use-case" class="wiki-anchor">¶</a></h2>
<p>I sometimes use OpenStruct as a JSON API response wrapper.<br>
It's useful to use method call instead of key access (<code>obj[:key]</code>) because we can use <code>Symbol#to_proc</code> if it's a method (for example <code>users.map(&:id)</code>)</p>
<p>But I want to prevent typo for a key name. Currently <code>users.map(&:idd)</code> just returns <code>[nil,...]</code></p>
<p>Even if we have this <code>exception</code> option, we can't enable this option for JSON parser easily though:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="ss">object_class: </span><span class="no">Class</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">OpenStruct</span><span class="p">)</span> <span class="p">{</span> <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="nb">hash</span><span class="p">);</span> <span class="k">super</span><span class="p">(</span><span class="nb">hash</span><span class="p">,</span> <span class="ss">exception: </span><span class="kp">true</span><span class="p">);</span> <span class="k">end</span> <span class="p">})</span>
</code></pre>
<p>What do you think?</p>
<hr>
<p>I've searched with "openstruct nomethoderror" on bugs.ruby-lang.org though, please let me know if it's duplicated.<br>
<a href="https://bugs.ruby-lang.org/search?utf8=%E2%9C%93&scope=&q=nomethoderror+openstruct" class="external">https://bugs.ruby-lang.org/search?utf8=%E2%9C%93&scope=&q=nomethoderror+openstruct</a></p> Ruby master - Misc #15802 (Open): Reduce the minimum string buffer size from 127 to 63 byteshttps://bugs.ruby-lang.org/issues/158022019-04-27T16:40:14Zmethodmissing (Lourens Naudé)lourens@bearmetal.eu
<p>References Github PR <a href="https://github.com/ruby/ruby/pull/2151" class="external">https://github.com/ruby/ruby/pull/2151</a> - another small change, but posting here for further discussion.</p>
<p>While having a look through <code>String</code> specific allocation paths with <a href="http://valgrind.org/docs/manual/dh-manual.html#dh-manual.overview" class="external">dhat</a> on redmine I noticed many string buffer use cases actually need way less than the current <code>128</code> byte minimum size (127 current minimum size + sentinel).</p>
<p>These auxiliary buffers are malloc heap specific as the <code>String</code> type is not supported by the transient heap due to complexity.</p>
<a name="How-to-interpret-the-DHAT-output"></a>
<h4 >How to interpret the DHAT output<a href="#How-to-interpret-the-DHAT-output" class="wiki-anchor">¶</a></h4>
<p>From the example output below, we can draw the following conclusions for the specific allocation site leading up to <code>rb_str_buf_new</code>:</p>
<ul>
<li>Total allocated size of <code>434944</code> bytes with a very low read and write access ratio under 25%</li>
<li>The buffer is thus 75% larger than it should be for this particular site (more examples further down below)</li>
<li>Short lived as expected from a buffer use case, but did occupy non-insignificant heap space still for a fair amount of time</li>
<li>The <code>0</code>s at the tail end of the output represent memory never accessed (rows are byte offsets)</li>
<li>As an aside, this particular string's first few characters are <code>hot</code> (accessed more frequently than the tail end)</li>
</ul>
<pre><code>==26579== -------------------- 95 of 300 --------------------
==26579== max-live: 330,368 in 2,581 blocks
==26579== tot-alloc: 434,944 in 3,398 blocks (avg size 128.00)
==26579== deaths: 3,347, at avg age 368,102,626 (2.64% of prog lifetime)
==26579== acc-ratios: 0.22 rd, 0.25 wr (97,275 b-read, 110,341 b-written)
==26579== at 0x4C2DECF: malloc (in /usr/lib/valgrind/vgpreload_exp-dhat-amd64-linux.so)
==26579== by 0x1521D3: objspace_xmalloc0 (gc.c:9407)
==26579== by 0x284A9B: rb_str_buf_new (string.c:1331)
==26579== by 0x31B9F7: rb_ary_join (array.c:2331)
==26579== by 0x2E5B4E: vm_call_cfunc_with_frame (vm_insnhelper.c:2207)
==26579== by 0x2E5B4E: vm_call_cfunc (vm_insnhelper.c:2225)
==26579== by 0x2F7C7C: vm_sendish (vm_insnhelper.c:3623)
==26579== by 0x2F7C7C: vm_exec_core (insns.def:789)
==26579== by 0x2EE34D: rb_vm_exec (vm.c:1892)
==26579== by 0x2EEEED: invoke_iseq_block_from_c (vm.c:1104)
==26579== by 0x2EEEED: invoke_block_from_c_bh (vm.c:1122)
==26579== by 0x2EEEED: vm_yield (vm.c:1167)
==26579== by 0x2EEEED: rb_yield_0 (vm_eval.c:980)
==26579== by 0x2EEEED: rb_yield_1 (vm_eval.c:986)
==26579== by 0x2EEEED: rb_yield (vm_eval.c:996)
==26579== by 0x31153B: rb_ary_each (array.c:2087)
==26579== by 0x2E5B4E: vm_call_cfunc_with_frame (vm_insnhelper.c:2207)
==26579== by 0x2E5B4E: vm_call_cfunc (vm_insnhelper.c:2225)
==26579== by 0x2F7D2B: vm_sendish (vm_insnhelper.c:3623)
==26579== by 0x2F7D2B: vm_exec_core (insns.def:771)
==26579== by 0x2EE34D: rb_vm_exec (vm.c:1892)
==26579==
==26579== Aggregated access counts by offset:
==26579==
==26579== [ 0] 11407 8731 9660 11112 11171 11724 13165 13609 10826 10998 11436 11420 11405 10295 9710 9316
==26579== [ 16] 5664 4959 3874 3607 2965 2395 1908 1509 1285 967 597 261 149 141 140 124
==26579== [ 32] 73 57 56 55 55 55 54 52 51 51 51 51 51 51 51 51
==26579== [ 48] 34 34 34 34 34 34 17 0 0 0 0 0 0 0 0 0
==26579== [ 64] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 80] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 96] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 112] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
</code></pre>
<a name="Why-lower-is-better"></a>
<h4 >Why lower is better<a href="#Why-lower-is-better" class="wiki-anchor">¶</a></h4>
<p>The easiest reproducible case from the benchmark suite is the <code>require</code> benchmark (the allocation site below is from Rails though - DHAT is very slow and doesn't make sense in context of a benchmark):</p>
<pre><code>==28383== -------------------- 572 of 600 --------------------
==28383== max-live: 36,992 in 289 blocks
==28383== tot-alloc: 91,520 in 715 blocks (avg size 128.00)
==28383== deaths: 553, at avg age 908,212,488 (8.68% of prog lifetime)
==28383== acc-ratios: 6.15 rd, 0.41 wr (563,074 b-read, 37,525 b-written)
==28383== at 0x4C2DECF: malloc (in /usr/lib/valgrind/vgpreload_exp-dhat-amd64-linux.so)
==28383== by 0x1521D3: objspace_xmalloc0 (gc.c:9407)
==28383== by 0x284A9B: rb_str_buf_new (string.c:1331)
==28383== by 0x290D56: str_gsub (string.c:5163)
==28383== by 0x2E5B4E: vm_call_cfunc_with_frame (vm_insnhelper.c:2207)
==28383== by 0x2E5B4E: vm_call_cfunc (vm_insnhelper.c:2225)
==28383== by 0x2F7C7C: vm_sendish (vm_insnhelper.c:3623)
==28383== by 0x2F7C7C: vm_exec_core (insns.def:789)
==28383== by 0x2EE34D: rb_vm_exec (vm.c:1892)
==28383== by 0x18B336: rb_load_internal0 (load.c:612)
==28383== by 0x18E1B0: rb_require_internal (load.c:1028)
==28383== by 0x18E3B2: rb_require_safe (load.c:1074)
==28383== by 0x18E3B2: rb_f_require (load.c:821)
==28383== by 0x2E5B4E: vm_call_cfunc_with_frame (vm_insnhelper.c:2207)
==28383== by 0x2E5B4E: vm_call_cfunc (vm_insnhelper.c:2225)
==28383== by 0x2F1F42: vm_call_method (vm_insnhelper.c:2712)
==28383==
==28383== Aggregated access counts by offset:
==28383==
==28383== [ 0] 17936 15574 14945 15051 14538 15487 15599 15077 14658 14483 14826 14849 15232 15238 15522 15310
==28383== [ 16] 15055 15020 15143 15156 15271 14807 14656 14271 14051 13761 13365 13156 12756 12530 12302 12002
==28383== [ 32] 7652 7427 7106 6807 6594 6315 6044 5932 5750 5606 5520 5439 5347 5237 5174 5095
==28383== [ 48] 2252 2211 2158 2128 2117 2088 2075 2045 2034 2018 2006 1992 1974 1973 1964 1964
==28383== [ 64] 183 183 183 183 183 183 183 183 183 183 183 183 183 183 183 183
==28383== [ 80] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28383== [ 96] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28383== [ 112] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
</code></pre>
<pre><code>lourens@CarbonX1:~/src/ruby/ruby$ /usr/local/bin/ruby --disable=gems -rrubygems -I./benchmark/lib ./benchmark/benchmark-driver/exe/benchmark-driver --executables="compare-ruby::~/src/ruby/trunk/ruby --disable=gems -I.ext/common --disable-gem" --executables="built-ruby::./miniruby -I./lib -I. -I.ext/common -r./prelude --disable-gem" -v --repeat-count=24 -r ips $(ls ./benchmark/*require.{yml,rb} 2>/dev/null)
compare-ruby: ruby 2.7.0dev (2019-04-25 trunk 9bfc185a0d) [x86_64-linux]
built-ruby: ruby 2.7.0dev (2019-04-25 lower-str-buf-.. 9bfc185a0d) [x86_64-linux]
Calculating -------------------------------------
compare-ruby built-ruby
require 1.870 2.408 i/s - 1.000 times in 0.534865s 0.415268s
Comparison:
require
built-ruby: 2.4 i/s
compare-ruby: 1.9 i/s - 1.29x slower
lourens@CarbonX1:~/src/ruby/ruby$ /usr/local/bin/ruby --disable=gems -rrubygems -I./benchmark/lib ./benchmark/benchmark-driver/exe/benchmark-driver --executables="compare-ruby::~/src/ruby/trunk/ruby --disable=gems -I.ext/common --disable-gem" --executables="built-ruby::./miniruby -I./lib -I. -I.ext/common -r./prelude --disable-gem" -v --repeat-count=24 -r memory $(ls ./benchmark/*require.{yml,rb} 2>/dev/null)
compare-ruby: ruby 2.7.0dev (2019-04-25 trunk 9bfc185a0d) [x86_64-linux]
built-ruby: ruby 2.7.0dev (2019-04-25 lower-str-buf-.. 9bfc185a0d) [x86_64-linux]
Calculating -------------------------------------
compare-ruby built-ruby
require 28.128M 26.932M bytes - 1.000 times
Comparison:
require
built-ruby: 26932000.0 bytes
compare-ruby: 28128000.0 bytes - 1.04x larger
</code></pre>
<p>Also the <code>hash_aref_dsym_long</code> benchmark has significant memory reduction:</p>
<pre><code>lourens@CarbonX1:~/src/ruby/ruby$ /usr/local/bin/ruby --disable=gems -rrubygems -I./benchmark/lib ./benchmark/benchmark-driver/exe/benchmark-driver --executables="compare-ruby::~/src/ruby/trunk/ruby --disable=gems -I.ext/common --disable-gem" --executables="built-ruby::./miniruby -I./lib -I. -I.ext/common -r./prelude --disable-gem" -v --repeat-count=6 -r memory $(ls ./benchmark/hash_aref_dsym_long.{yml,rb} 2>/dev/null)
compare-ruby: ruby 2.7.0dev (2019-04-26 trunk 5689c46457) [x86_64-linux]
built-ruby: ruby 2.7.0dev (2019-04-26 lower-str-buf-.. 9abd605533) [x86_64-linux]
last_commit=Reduce the minimum string buffer size from 127 to 63 bytes
Calculating -------------------------------------
compare-ruby built-ruby
hash_aref_dsym_long 117.580M 104.984M bytes - 1.000 times
Comparison:
hash_aref_dsym_long
built-ruby: 104984000.0 bytes
compare-ruby: 117580000.0 bytes - 1.12x larger
</code></pre>
<a name="Other-allocation-sites-of-note"></a>
<h4 >Other allocation sites of note<a href="#Other-allocation-sites-of-note" class="wiki-anchor">¶</a></h4>
<pre><code>==26579== -------------------- 98 of 300 --------------------
==26579== max-live: 323,456 in 2,527 blocks
==26579== tot-alloc: 402,816 in 3,147 blocks (avg size 128.00)
==26579== deaths: 3,147, at avg age 377,614,197 (2.71% of prog lifetime)
==26579== acc-ratios: 0.21 rd, 0.16 wr (87,620 b-read, 64,622 b-written)
==26579== at 0x4C2DECF: malloc (in /usr/lib/valgrind/vgpreload_exp-dhat-amd64-linux.so)
==26579== by 0x1521D3: objspace_xmalloc0 (gc.c:9407)
==26579== by 0x284A9B: rb_str_buf_new (string.c:1331)
==26579== by 0x294584: rb_str_inspect (string.c:5911)
==26579== by 0x2F33F8: vm_call0_cfunc_with_frame (vm_eval.c:86)
==26579== by 0x2F33F8: vm_call0_cfunc (vm_eval.c:100)
==26579== by 0x2F33F8: vm_call0_body.constprop.410 (vm_eval.c:132)
==26579== by 0x2FE4CE: rb_vm_call0 (vm_eval.c:60)
==26579== by 0x2FE4CE: rb_call0 (vm_eval.c:309)
==26579== by 0x2FE4CE: rb_call (vm_eval.c:603)
==26579== by 0x2FE4CE: rb_funcall_with_block (vm_eval.c:857)
==26579== by 0x2EEFBE: vm_yield_with_symbol (vm_insnhelper.c:2869)
==26579== by 0x2EEFBE: invoke_block_from_c_bh (vm.c:1131)
==26579== by 0x2EEFBE: vm_yield (vm.c:1167)
==26579== by 0x2EEFBE: rb_yield_0 (vm_eval.c:980)
==26579== by 0x2EEFBE: rb_yield_1 (vm_eval.c:986)
==26579== by 0x2EEFBE: rb_yield (vm_eval.c:996)
==26579== by 0x317627: rb_ary_collect_bang (array.c:3052)
==26579== by 0x2E5B4E: vm_call_cfunc_with_frame (vm_insnhelper.c:2207)
==26579== by 0x2E5B4E: vm_call_cfunc (vm_insnhelper.c:2225)
==26579== by 0x2F7D2B: vm_sendish (vm_insnhelper.c:3623)
==26579== by 0x2F7D2B: vm_exec_core (insns.def:771)
==26579== by 0x2EE34D: rb_vm_exec (vm.c:1892)
==26579== by 0x2EEEED: invoke_iseq_block_from_c (vm.c:1104)
==26579== by 0x2EEEED: invoke_block_from_c_bh (vm.c:1122)
==26579== by 0x2EEEED: vm_yield (vm.c:1167)
==26579== by 0x2EEEED: rb_yield_0 (vm_eval.c:980)
==26579== by 0x2EEEED: rb_yield_1 (vm_eval.c:986)
==26579== by 0x2EEEED: rb_yield (vm_eval.c:996)
==26579==
==26579== Aggregated access counts by offset:
==26579==
==26579== [ 0] 13063 14338 12631 14007 13323 12720 11984 11344 9232 7280 6288 5776 4256 3856 3584 2976
==26579== [ 16] 1968 1216 1296 720 160 48 48 48 64 16 0 0 0 0 0 0
==26579== [ 32] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 48] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 64] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 80] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 96] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 112] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
</code></pre>
<pre><code>==26579== -------------------- 186 of 300 --------------------
==26579== max-live: 155,136 in 1,212 blocks
==26579== tot-alloc: 155,136 in 1,212 blocks (avg size 128.00)
==26579== deaths: 651, at avg age 245,150,551 (1.75% of prog lifetime)
==26579== acc-ratios: 1.63 rd, 0.33 wr (253,660 b-read, 51,700 b-written)
==26579== at 0x4C2DECF: malloc (in /usr/lib/valgrind/vgpreload_exp-dhat-amd64-linux.so)
==26579== by 0x1521D3: objspace_xmalloc0 (gc.c:9407)
==26579== by 0x284A9B: rb_str_buf_new (string.c:1331)
==26579== by 0x13AA2E: rb_file_join (file.c:4732)
==26579== by 0x2E5B4E: vm_call_cfunc_with_frame (vm_insnhelper.c:2207)
==26579== by 0x2E5B4E: vm_call_cfunc (vm_insnhelper.c:2225)
==26579== by 0x2F7C7C: vm_sendish (vm_insnhelper.c:3623)
==26579== by 0x2F7C7C: vm_exec_core (insns.def:789)
==26579== by 0x2EE34D: rb_vm_exec (vm.c:1892)
==26579== by 0x2EEEED: invoke_iseq_block_from_c (vm.c:1104)
==26579== by 0x2EEEED: invoke_block_from_c_bh (vm.c:1122)
==26579== by 0x2EEEED: vm_yield (vm.c:1167)
==26579== by 0x2EEEED: rb_yield_0 (vm_eval.c:980)
==26579== by 0x2EEEED: rb_yield_1 (vm_eval.c:986)
==26579== by 0x2EEEED: rb_yield (vm_eval.c:996)
==26579== by 0x374412: dir_yield (dir.c:803)
==26579== by 0x374412: dir_each_entry (dir.c:860)
==26579== by 0x374412: dir_each (dir.c:830)
==26579== by 0x1355D2: rb_ensure (eval.c:1076)
==26579== by 0x373447: dir_foreach (dir.c:2955)
==26579== by 0x2E5B4E: vm_call_cfunc_with_frame (vm_insnhelper.c:2207)
==26579== by 0x2E5B4E: vm_call_cfunc (vm_insnhelper.c:2225)
==26579==
==26579== Aggregated access counts by offset:
==26579==
==26579== [ 0] 17075 17890 16143 17188 15855 18234 17616 19067 13136 11474 10379 11350 10094 9420 8556 7614
==26579== [ 16] 5325 5125 5030 4865 3582 2982 3010 3018 2997 3011 3056 3104 2695 2748 2696 2680
==26579== [ 32] 1741 1726 1664 1612 1285 1191 1138 1067 1043 1008 984 983 971 985 972 970
==26579== [ 48] 565 562 568 559 560 557 557 557 557 557 557 557 557 557 557 557
==26579== [ 64] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
==26579== [ 80] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 96] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 112] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
</code></pre>
<pre><code>==28716== -------------------- 64 of 300 --------------------
==28716== max-live: 273,280 in 2,135 blocks
==28716== tot-alloc: 446,464 in 3,488 blocks (avg size 128.00)
==28716== deaths: 2,277, at avg age 365,758,007 (3.44% of prog lifetime)
==28716== acc-ratios: 0.21 rd, 0.15 wr (96,380 b-read, 71,208 b-written)
==28716== at 0x4C2DECF: malloc (in /usr/lib/valgrind/vgpreload_exp-dhat-amd64-linux.so)
==28716== by 0x1521D3: objspace_xmalloc0 (gc.c:9407)
==28716== by 0x284A9B: rb_str_buf_new (string.c:1331)
==28716== by 0x294584: rb_str_inspect (string.c:5911)
==28716==
==28716== Aggregated access counts by offset:
==28716==
==28716== [ 0] 14382 15824 13909 15391 14767 14067 13241 12472 10180 7932 6842 6270 4714 4213 3909 3280
==28716== [ 16] 2173 1349 1386 810 216 63 54 55 68 20 1 0 0 0 0 0
==28716== [ 32] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 48] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 64] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 80] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 96] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 112] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
</code></pre>
<pre><code>==28716== -------------------- 276 of 300 --------------------
==28716== max-live: 19,712 in 154 blocks
==28716== tot-alloc: 146,432 in 1,144 blocks (avg size 128.00)
==28716== deaths: 1,115, at avg age 150,688,929 (1.41% of prog lifetime)
==28716== acc-ratios: 0.06 rd, 0.08 wr (9,024 b-read, 12,049 b-written)
==28716== at 0x4C2DECF: malloc (in /usr/lib/valgrind/vgpreload_exp-dhat-amd64-linux.so)
==28716== by 0x1521D3: objspace_xmalloc0 (gc.c:9407)
==28716== by 0x284A9B: rb_str_buf_new (string.c:1331)
==28716== by 0x23B70C: rb_reg_regsub (re.c:3820)
==28716==
==28716== Aggregated access counts by offset:
==28716==
==28716== [ 0] 3569 4271 3304 1590 670 640 673 692 537 526 525 518 502 482 465 443
==28716== [ 16] 223 203 182 153 127 113 101 85 71 63 57 52 49 48 44 38
==28716== [ 32] 14 9 7 6 5 4 4 4 3 1 0 0 0 0 0 0
==28716== [ 48] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 64] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 80] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 96] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 112] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
</code></pre>
<pre><code>==29686== -------------------- 391 of 600 --------------------
==29686== max-live: 8,192 in 64 blocks
==29686== tot-alloc: 9,472 in 74 blocks (avg size 128.00)
==29686== deaths: 74, at avg age 207,459,973 (1.96% of prog lifetime)
==29686== acc-ratios: 0.21 rd, 0.17 wr (1,998 b-read, 1,628 b-written)
==29686== at 0x4C2DECF: malloc (in /usr/lib/valgrind/vgpreload_exp-dhat-amd64-linux.so)
==29686== by 0x1521D3: objspace_xmalloc0 (gc.c:9407)
==29686== by 0x284A9B: rb_str_buf_new (string.c:1331)
==29686== by 0x30BB8A: inspect_ary (array.c:2379)
==29686==
==29686== Aggregated access counts by offset:
==29686==
==29686== [ 0] 296 296 296 370 370 370 370 370 296 222 296 74 0 0 0 0
==29686== [ 16] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==29686== [ 32] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==29686== [ 48] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==29686== [ 64] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==29686== [ 80] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==29686== [ 96] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==29686== [ 112] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
</code></pre>
<a name="Rails-specific-redmine-boot"></a>
<h4 >Rails specific - redmine boot<a href="#Rails-specific-redmine-boot" class="wiki-anchor">¶</a></h4>
<p>Booting redmine only, no real work done otherwise - about <code>101720</code> bytes different in current malloc sizes. I understand <code>GC.malloc_allocated_size</code> to reflect the current delta between <code>xmalloc</code> and <code>xfree</code>, but may be wrong. And that value is not representative of total malloc heap churn, judging by the much higher total allocated values coming back from <a href="https://github.com/ruby/ruby/pull/2151#issuecomment-487300456" class="external">valgrind</a>.</p>
<pre><code>lourens@CarbonX1:~/src/redmine$ bundle exec rails c -e production
/home/lourens/src/redmine/vendor/bundle/ruby/2.7.0/gems/activerecord-5.2.1.1/lib/active_record/associations/builder/collection_association.rb:26: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead
Loading production environment (Rails 5.2.1.1)
irb(main):001:0> RUBY_DESCRIPTION
=> "ruby 2.7.0dev (2019-04-26 trunk 5689c46457) [x86_64-linux]"
irb(main):002:0> GC.start
=> nil
irb(main):003:0> GC.malloc_allocated_size
=> 74907128
</code></pre>
<pre><code>lourens@CarbonX1:~/src/redmine$ bundle exec rails c -e production
/home/lourens/src/redmine/vendor/bundle/ruby/2.7.0/gems/activerecord-5.2.1.1/lib/active_record/associations/builder/collection_association.rb:26: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead
Loading production environment (Rails 5.2.1.1)
irb(main):001:0> RUBY_DESCRIPTION
=> "ruby 2.7.0dev (2019-04-26 lower-str-buf-.. 9abd605533) [x86_64-linux]"
irb(main):002:0> GC.start
=> nil
irb(main):003:0> GC.malloc_allocated_size
=> 74805408
</code></pre>
<a name="Rails-specific-some-requests-workload"></a>
<h4 >Rails specific - some requests / workload<a href="#Rails-specific-some-requests-workload" class="wiki-anchor">¶</a></h4>
<p>Same sequence of redmine requests - 6 for this branch and trunk respectively using this as a simple initializer for reporting on exit, a <code>228600</code> bytes difference.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">if</span> <span class="no">GC</span><span class="p">.</span><span class="nf">respond_to?</span><span class="p">(</span><span class="ss">:malloc_allocated_size</span><span class="p">)</span>
<span class="nb">at_exit</span> <span class="k">do</span>
<span class="nb">p</span> <span class="s2">"</span><span class="si">#{</span><span class="no">RUBY_DESCRIPTION</span><span class="si">}</span><span class="s2"> GC.malloc_allocated_size: </span><span class="si">#{</span><span class="no">GC</span><span class="p">.</span><span class="nf">malloc_allocated_size</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<pre><code>[2019-04-25 23:42:43] INFO WEBrick 1.4.2
[2019-04-25 23:42:43] INFO ruby 2.7.0 (2019-04-26) [x86_64-linux]
[2019-04-25 23:42:43] INFO WEBrick::HTTPServer#start: pid=31335 port=3000
127.0.0.1 - - [25/Apr/2019:23:42:48 WEST] "GET / HTTP/1.1" 200 4373
http://localhost:3000/news -> /
127.0.0.1 - - [25/Apr/2019:23:42:49 WEST] "GET /projects HTTP/1.1" 200 5470
http://localhost:3000/ -> /projects
127.0.0.1 - - [25/Apr/2019:23:42:51 WEST] "GET /activity HTTP/1.1" 200 7373
http://localhost:3000/projects -> /activity
127.0.0.1 - - [25/Apr/2019:23:42:51 WEST] "GET /issues HTTP/1.1" 200 19195
http://localhost:3000/activity -> /issues
127.0.0.1 - - [25/Apr/2019:23:42:52 WEST] "GET /time_entries HTTP/1.1" 200 12508
http://localhost:3000/issues -> /time_entries
127.0.0.1 - - [25/Apr/2019:23:42:53 WEST] "GET /issues/gantt HTTP/1.1" 200 22597
http://localhost:3000/time_entries -> /issues/gantt
127.0.0.1 - - [25/Apr/2019:23:42:54 WEST] "GET /issues/calendar HTTP/1.1" 200 16712
http://localhost:3000/issues/gantt -> /issues/calendar
127.0.0.1 - - [25/Apr/2019:23:42:54 WEST] "GET /news HTTP/1.1" 200 5472
http://localhost:3000/issues/calendar -> /news
^C[2019-04-25 23:42:58] INFO going to shutdown ...
[2019-04-25 23:42:59] INFO WEBrick::HTTPServer#start done.
Exiting
"ruby 2.7.0dev (2019-04-26 trunk 5689c46457) [x86_64-linux] GC.malloc_allocated_size: 84901440"
</code></pre>
<pre><code>[2019-04-25 23:41:51] INFO WEBrick 1.4.2
[2019-04-25 23:41:51] INFO ruby 2.7.0 (2019-04-26) [x86_64-linux]
[2019-04-25 23:41:51] INFO WEBrick::HTTPServer#start: pid=31029 port=3000
127.0.0.1 - - [25/Apr/2019:23:41:59 WEST] "GET / HTTP/1.1" 200 4373
http://localhost:3000/activity -> /
127.0.0.1 - - [25/Apr/2019:23:42:02 WEST] "GET /projects HTTP/1.1" 200 5470
http://localhost:3000/ -> /projects
127.0.0.1 - - [25/Apr/2019:23:42:04 WEST] "GET /activity HTTP/1.1" 200 7373
http://localhost:3000/projects -> /activity
127.0.0.1 - - [25/Apr/2019:23:42:05 WEST] "GET /issues HTTP/1.1" 200 19195
http://localhost:3000/activity -> /issues
127.0.0.1 - - [25/Apr/2019:23:42:06 WEST] "GET /time_entries HTTP/1.1" 200 12508
http://localhost:3000/issues -> /time_entries
127.0.0.1 - - [25/Apr/2019:23:42:07 WEST] "GET /issues/gantt HTTP/1.1" 200 22597
http://localhost:3000/time_entries -> /issues/gantt
127.0.0.1 - - [25/Apr/2019:23:42:07 WEST] "GET /javascripts/raphael.js?1543965852 HTTP/1.1" 200 90648
http://localhost:3000/issues/gantt -> /javascripts/raphael.js?1543965852
127.0.0.1 - - [25/Apr/2019:23:42:08 WEST] "GET /issues/calendar HTTP/1.1" 200 16712
http://localhost:3000/issues/gantt -> /issues/calendar
127.0.0.1 - - [25/Apr/2019:23:42:09 WEST] "GET /news HTTP/1.1" 200 5472
http://localhost:3000/issues/calendar -> /news
^C[2019-04-25 23:42:14] INFO going to shutdown ...
[2019-04-25 23:42:15] INFO WEBrick::HTTPServer#start done.
Exiting
"ruby 2.7.0dev (2019-04-26 lower-str-buf-.. 9abd605533) [x86_64-linux] GC.malloc_allocated_size: 84672840"
</code></pre> Ruby master - Feature #15778 (Open): Expose an API to pry-open the stack frames in Rubyhttps://bugs.ruby-lang.org/issues/157782019-04-20T02:27:49Zgsamokovarov (Genadi Samokovarov)gsamokovarov@gmail.com
<p>Hello,</p>
<p>I'm the maintainer of the web-console (<a href="https://github.com/rails/web-console/" class="external">https://github.com/rails/web-console/</a>) gem, where one of our features is to jump between the frames in which an error occurred. To accomplish this, I currently use the Debug Inspector CRuby API. I think we should expose this functionality in Rubyland, so tools like web-console don't need to resort to C code for this. This also makes it quite harder for me to support different implementations like JRuby or TruffleRuby as everyone is having a different way to create Ruby Binding objects that represent the frames.</p>
<p>Here the API ideas:</p>
<p>Add <code>Thread::Backtrace::Location#binding</code> method that can create a binding for a specific caller of the current frame. We can reuse the existing <code>Kernel.caller_locations</code> method to generate the array of <code>Thread::Backtrace::Location</code> objects. We can optionally have the <code>Kernel.caller_locations(debug: true)</code> argument if we cannot generate the bindings lazily on the VM that can instruct the VM to do the slower operation.</p>
<ul>
<li>
<code>Thread::Backtrace::Location#binding</code> returns <code>Binding|nil</code>. Nil result may mean that the current location is a C frame or a JITted/optimized frame and we cannot debug it.</li>
</ul>
<p>We can also expose the DebugInspector API directly, as done in the <a href="https://github.com/banister/debug_inspector" class="external">https://github.com/banister/debug_inspector</a> gem, but for tools like web-console, we'd need to map the bindings with the backtrace, as we cannot generate Bindings for every frame (C frames) and this needs to be done in application code, so I think the <code>Thread::Backtrace::Location#binding</code> is the better API for Ruby-land.</p>
<p>Such API can help us eventually write most of our debuggers in Ruby as right now we don't have a way to do Post-Mortem debugging without native code or even start our debuggers without monkey-patching <code>Binding</code>.</p>
<p>I have presented this idea in a RubyKaigi's 2019 talk called "Writing Debuggers in Plain Ruby", you can check-out the slides for more context: <a href="http://kaigi-debuggers-in-ruby.herokuapp.com" class="external">http://kaigi-debuggers-in-ruby.herokuapp.com</a>.</p> Ruby master - Bug #15764 (Open): Whitespace and control characters should not be permitted in tokenshttps://bugs.ruby-lang.org/issues/157642019-04-11T20:59:47ZBatmanAoD (Kyle Strand)kyle.j.strand@gmail.com
<p>As of Ruby 2.5.1p57, it appears that all valid Unicode code-points above 128 are permitted in tokens. This includes whitespace and control characters.</p>
<p>This was demonstrated here: <a href="https://gist.github.com/qrohlf/7045823" class="external">https://gist.github.com/qrohlf/7045823</a></p>
<p>I have attached the raw download from the above gist.</p>
<p>The issue has been discussed on StackOverflow: <a href="https://stackoverflow.com/q/34455427/1858225" class="external">https://stackoverflow.com/q/34455427/1858225</a></p>
<p>I would say this is arguably a bug, but I am marking this ticket as a "feature" since the current behavior could be considered by-design.</p> Ruby master - Feature #15554 (Open): warn/error passing a block to a method which never use a blockhttps://bugs.ruby-lang.org/issues/155542019-01-22T04:48:10Zko1 (Koichi Sasada)
<a name="Abstract"></a>
<h1 >Abstract<a href="#Abstract" class="wiki-anchor">¶</a></h1>
<p>Warn or raise an ArgumentError if block is passed to a method which does not use a block.<br>
In other words, detect "block user methods" implicitly and only "block user methods" can accept a block.</p>
<a name="Background"></a>
<h1 >Background<a href="#Background" class="wiki-anchor">¶</a></h1>
<p>Sometimes, we pass a block to a method which ignores the passed block accidentally.</p>
<pre><code>def my_open(name)
open(name)
end
# user hopes it works as Kernel#open which invokes a block with opened file.
my_open(name){|f| important_work_with f }
# but simply ignored...
</code></pre>
<p>To solve this issue, this feature request propose showing warnings or raising an exception on such case.</p>
<p>Last developer's meeting, matz proposed <code>&nil</code> which declares this method never receive a block. It is explicit, but it is tough to add this <code>&nil</code> parameter declaration to all of methods (do you want to add it to <code>def []=(i, e, &nil)</code>?).<br>
(I agree <code>&nil</code> is valuable on some situations)</p>
<a name="Spec"></a>
<h1 >Spec<a href="#Spec" class="wiki-anchor">¶</a></h1>
<a name="Define-use-a-block-methods"></a>
<h2 >Define "use a block" methods<a href="#Define-use-a-block-methods" class="wiki-anchor">¶</a></h2>
<p>We need to define which method accepts a block and which method does not.</p>
<ul>
<li>(1) method has a block parameter (<code>&b</code>)</li>
<li>(2) method body has `yield'</li>
<li>(3) method body has <code>super</code> (ZSUPER in internal terminology) or <code>super(...)</code>
</li>
<li>(4) method body has singleton method (optional)</li>
</ul>
<p>(1) and (2) is very clear. I need to explain about (3) and (4).</p>
<p>(3). <code>super</code> (ZSUPER) passes all parameters as arguments. So there is no surprise that which can accept <code>block</code>.<br>
However <code>super(...)</code> also passes a block if no explicit block passing (like <code>super(){}</code> or <code>super(&b)</code>) are written.<br>
I'm not sure we need to continue this strange specification, but to keep compatibility depending this spec, I add this rule.</p>
<p>(4). surprisingly, the following code invoke a block:</p>
<pre><code>def foo
class << Object.new
yield
end
end
foo{ p :ok } #=> :ok
</code></pre>
<p>I'm also not sure we need to keep this spec, but to allow this spec, I added (4) rule.<br>
Strictly speaking, it is not required, but we don't keep the link from singleton class ISeq to lexical parent iseq now, so I added it.</p>
<a name="Exceptional-cases"></a>
<h2 >Exceptional cases<a href="#Exceptional-cases" class="wiki-anchor">¶</a></h2>
<p>A method called by <code>super</code> doesn<code>t warn warning even if this method doesn't use a block. The rule (3) can pass blocks easily and there are many methods don</code>t use a block.</p>
<p>So my patch ignores callings by <code>super</code>.</p>
<a name="corner-cases"></a>
<h2 >corner cases<a href="#corner-cases" class="wiki-anchor">¶</a></h2>
<p>There are several cases to use block without (1)-(4) rules.</p>
<h3>
<code>Proc.new/proc/lambda</code> without a block</h3>
<p>Now it was deprecated in r66772 (<a class="changeset" title="proc.c: proc without block * proc.c (proc_new): promoted lambda/proc/Proc.new with no block in..." href="https://bugs.ruby-lang.org/projects/ruby-master/repository/git/revisions/9f1fb0a17febc59356d58cef5e98db61a3c03550">9f1fb0a17febc59356d58cef5e98db61a3c03550</a>).<br>
Related discussion: [Bug <a class="issue tracker-1 status-6 priority-4 priority-default closed" title="Bug: Proc.new with no block shouldn't always warn (Rejected)" href="https://bugs.ruby-lang.org/issues/15539">#15539</a>]</p>
<a name="block_given"></a>
<h3 ><code>block_given?</code><a href="#block_given" class="wiki-anchor">¶</a></h3>
<p><code>block_given?</code> expects block, but I believe we use it with <code>yield</code> or a block parameter.<br>
If you know the usecase without them, please tell us.</p>
<h3>
<code>yield</code> in <code>eval</code>
</h3>
<p>We can't know <code>yield</code> (or (3), (4) rule) in an <code>eval</code> evaluating string at calling time.</p>
<pre><code>def foo
eval('yield`)
end
foo{} # at calling time,
# we can't know the method foo can accept a block or not.
</code></pre>
<p>So I added a warning to use <code>yield</code> in <code>eval</code> like that: <code>test.rb:4: warning: use yield in eval will not be supported in Ruby 3.</code></p>
<p>Workaround is use a block parameter explicitly.</p>
<pre><code>def foo &b
eval('b.call')
end
foo{ p :ok }
</code></pre>
<a name="Implementation"></a>
<h1 >Implementation<a href="#Implementation" class="wiki-anchor">¶</a></h1>
<p>Strategy is:</p>
<ul>
<li>[compile time] introduce <code>iseq::has_yield</code> field and check it if the iseq (or child iseq) contains <code>yield</code> (or something)</li>
<li>[calling time] if block is given, check <code>iseq::has_yield</code> flag and show warning (or raise an exception)</li>
</ul>
<p><a href="https://gist.github.com/ko1/c9148ad0224bf5befa3cc76ed2220c0b" class="external">https://gist.github.com/ko1/c9148ad0224bf5befa3cc76ed2220c0b</a></p>
<p>On this patch, now it raises an error to make it easy to detect.<br>
It is easy to switch to show the warning.</p>
<a name="Evaluation-and-discussion"></a>
<h1 >Evaluation and discussion<a href="#Evaluation-and-discussion" class="wiki-anchor">¶</a></h1>
<p>I tried to avoid ruby's tests.</p>
<p><a href="https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786" class="external">https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786</a></p>
<p>Here is a patch.</p>
<p>There are several patterns to avoid warnings.</p>
<a name="tests-for-block_given-Procnew-and-similar-without-block"></a>
<h2 >tests for <code>block_given?</code>, <code>Proc.new</code> (and similar) without block<a href="#tests-for-block_given-Procnew-and-similar-without-block" class="wiki-anchor">¶</a></h2>
<p>Add a dummy block parameter.<br>
It is test-specific issue.</p>
<h2>empty <code>each</code>
</h2>
<p>Some tests add <code>each</code> methods do not <code>yield</code>, like: <code>def each; end</code>.<br>
Maybe test-specific issue, and adding a dummy block parameter.</p>
<a name="Subtyping-duck-typing"></a>
<h2 >Subtyping / duck typing<a href="#Subtyping-duck-typing" class="wiki-anchor">¶</a></h2>
<p><a href="https://github.com/ruby/ruby/blob/c01a5ee85e2d6a7128cccafb143bfa694284ca87/lib/optparse.rb#L698" class="external">https://github.com/ruby/ruby/blob/c01a5ee85e2d6a7128cccafb143bfa694284ca87/lib/optparse.rb#L698</a></p>
<p>This <code>parse</code> method doesn't use <code>yield</code>, but other sub-type's <code>parse</code> methods use.</p>
<h2>
<code>super</code> with <code>new</code> method</h2>
<p><a href="https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786#file-tests-patch-L61" class="external">https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786#file-tests-patch-L61</a></p>
<p>This method override <code>Class#new</code> method and introduce a hook with block (yield a block in this hook code).</p>
<p><a href="https://github.com/ruby/ruby/blob/trunk/lib/rubygems/package/tar_writer.rb#L81" class="external">https://github.com/ruby/ruby/blob/trunk/lib/rubygems/package/tar_writer.rb#L81</a></p>
<p>In this method, call <code>super</code> and it also passing a block. However, called <code>initialize</code> doesn't use a block.</p>
<a name="Change-robustness"></a>
<h2 >Change robustness<a href="#Change-robustness" class="wiki-anchor">¶</a></h2>
<p>This change reduce robustness for API change.</p>
<p><code>Delegator</code> requires to support <code>__getobj__</code> for client classes.<br>
Now <code>__getobj__</code> should accept block but most of <code>__getobj__</code> clients do not call given block.</p>
<p><a href="https://github.com/ruby/ruby/blob/trunk/lib/delegate.rb#L80" class="external">https://github.com/ruby/ruby/blob/trunk/lib/delegate.rb#L80</a></p>
<p>This is because of delegator.rb's API change.</p>
<p><a href="https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786#file-tests-patch-L86" class="external">https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786#file-tests-patch-L86</a></p>
<p>Nobu says calling block is not required (ignoring a block is no problem) so it is not a bug for delegator client classes.</p>
<a name="Found-issues"></a>
<h2 >Found issues.<a href="#Found-issues" class="wiki-anchor">¶</a></h2>
<pre><code>[ 2945/20449] Rinda::TestRingServer#test_do_reply = 0.00 s
1) Error:
Rinda::TestRingServer#test_do_reply:
ArgumentError: passing block to the method "with_timeout" (defined at /home/ko1/src/ruby/trunk/test/rinda/test_rinda.rb:787) is never used.
/home/ko1/src/ruby/trunk/test/rinda/test_rinda.rb:635:in `test_do_reply'
[ 2946/20449] Rinda::TestRingServer#test_do_reply_local = 0.00 s
2) Error:
Rinda::TestRingServer#test_do_reply_local:
ArgumentError: passing block to the method "with_timeout" (defined at /home/ko1/src/ruby/trunk/test/rinda/test_rinda.rb:787) is never used.
/home/ko1/src/ruby/trunk/test/rinda/test_rinda.rb:657:in `test_do_reply_local'
[10024/20449] TestGemRequestSetGemDependencyAPI#test_platform_mswin = 0.01 s
3) Error:
TestGemRequestSetGemDependencyAPI#test_platform_mswin:
ArgumentError: passing block to the method "util_set_arch" (defined at /home/ko1/src/ruby/trunk/lib/rubygems/test_case.rb:1053) is never used.
/home/ko1/src/ruby/trunk/test/rubygems/test_gem_request_set_gem_dependency_api.rb:655:in `test_platform_mswin'
[10025/20449] TestGemRequestSetGemDependencyAPI#test_platforms = 0.01 s
4) Error:
TestGemRequestSetGemDependencyAPI#test_platforms:
ArgumentError: passing block to the method "util_set_arch" (defined at /home/ko1/src/ruby/trunk/lib/rubygems/test_case.rb:1053) is never used.
/home/ko1/src/ruby/trunk/test/rubygems/test_gem_request_set_gem_dependency_api.rb:711:in `test_platforms'
</code></pre>
<p>These 4 detection show the problem. <code>with_timeout</code> method (used in Rinda test) and <code>util_set_arch</code> method (used in Rubygems test) simply ignore the given block.<br>
So these tests are simply ignored.</p>
<p>I reported them. (<a href="https://github.com/rubygems/rubygems/issues/2601" class="external">https://github.com/rubygems/rubygems/issues/2601</a>)</p>
<a name="raise-an-error-or-show-a-warning"></a>
<h2 >raise an error or show a warning?<a href="#raise-an-error-or-show-a-warning" class="wiki-anchor">¶</a></h2>
<p>At least, Ruby 2.7 should show warning for this kind of violation with <code>-w</code>.<br>
How about for Ruby3?</p> Ruby master - Feature #15445 (Open): Reject '.123' in Float() methodhttps://bugs.ruby-lang.org/issues/154452018-12-21T00:16:38Zmrkn (Kenta Murata)muraken@gmail.com
<p>Since ruby 1.8, Ruby occurs a syntax error for "." floating literal.<br>
But Float() method accepts such form now.</p>
<p>I propose to reject "." form even in Float() method.</p> Ruby master - Feature #15408 (Open): Deprecate object_id and _id2refhttps://bugs.ruby-lang.org/issues/154082018-12-13T00:53:26Zheadius (Charles Nutter)headius@headius.com
<p>Ruby currently provides the object_id method to get a "identifier" for a given object. According to the documentation, this ID is the same for every object_id call against a given object, and guaranteed not to be the same as any other active (i.e. alive) object. However, no guarantee is made about the ID being reused for a future object after the original has been garbage collected.</p>
<p>As a result, object_id can't be used to uniquely identify any object that might be garbage collected, since that ID may be associated with a completely different object in the future.</p>
<p>Ruby also provides a method to go from an object_id to the object reference itself: ObjectSpace._id2ref. This method has been in Ruby for decades and is often used to implement a weak hashmap from ID to reference, since holding the ID will not keep the object alive. However due to the problems with object_id not actually being unique, it's possible for _id2ref to return a different object than originally had that ID as object slots are reused in the heap.</p>
<p>The only way to implement object_id safely (with idempotency guarantees) would be to assign to all objects a monotonically-increasing ID. Alternatively, this ID could be assigned lazily only for those objects on which the code calls object_id. JRuby implements object_id in this way currently.</p>
<p>The only way to implement _id2ref safely would be to have a mapping in memory from those monotonically-increasing IDs to the actual objects. This would have to be a weak mapping to prevent the objects from being garbage collected. JRuby currently only supports _id2ref via a flag, since the additional overhead of weakly tracking every requested object_id is extremely high. An alternative for MRI would be to implement _id2ref as a heap scan, as it is implemented in Rubinius. This would make it entirely unpractical due to the cost of scanning the heap for every ID lookup.</p>
<p>I propose that both methods should immediately be deprecated for removal in Ruby 3.0.</p>
<ul>
<li>They do not do what people expect.</li>
<li>They cannot reliably do what they claim to do.</li>
<li>They eventually lead to difficult-to-diagnose bugs in every possible use case.</li>
</ul>
<p>Put simply, both methods have always been broken in MRI and making them unbroken would render them useless.</p> Ruby master - Bug #15334 (Open): child_info_fork::abort: address space needed by 'emoji_iso2022_k...https://bugs.ruby-lang.org/issues/153342018-11-23T08:41:53Zduerst (Martin Dürst)duerst@it.aoyama.ac.jp
<p>When testing for upgrade to Unicode 11.0.0, I'm running into the following error:</p>
<pre><code>$$ ./ruby test/runner.rb test/ruby/test_m17n.rb
Run options:
# Running tests:
[124/139] TestM17N#test_utf_16_32_inspect(UTF-16BE) 1 [main] ruby 16076 child_info_fork::abort: address space needed by 'emoji_iso2022_kddi.so' (0x40000) is already occupied
3 [main] ruby 9736 child_info_fork::abort: address space needed by 'emoji_iso2022_kddi.so' (0x40000) is already occupied
2 [main] ruby 1108 child_info_fork::abort: address space needed by 'emoji_iso2022_kddi.so' (0x40000) is already occupied
2 [main] ruby 11476 child_info_fork::abort: address space needed by 'emoji_iso2022_kddi.so' (0x40000) is already occupied
2 [main] ruby 12308 child_info_fork::abort: address space needed by 'emoji_iso2022_kddi.so' (0x40000) is already occupied
3 [main] ruby 14096 child_info_fork::abort: address space needed by 'emoji_iso2022_kddi.so' (0x40000) is already occupied
2 [main] ruby 2392 child_info_fork::abort: address space needed by 'emoji_iso2022_kddi.so' (0x40000) is already occupied
3 [main] ruby 13132 child_info_fork::abort: address space needed by 'emoji_iso2022_kddi.so' (0x40000) is already occupied
2 [main] ruby 14772 child_info_fork::abort: address space needed by 'emoji_iso2022_kddi.so' (0x40000) is already occupied
4 [main] ruby 13780 child_info_fork::abort: address space needed by 'emoji_iso2022_kddi.so' (0x40000) is already occupied
4 [main] ruby 10312 child_info_fork::abort: address space needed by 'emoji_iso2022_kddi.so' (0x40000) is already occupied
3 [main] ruby 14936 child_info_fork::abort: address space needed by 'emoji_iso2022_kddi.so' (0x40000) is already occupied
1 [main] ruby 15944 child_info_fork::abort: address space needed by 'emoji_iso2022_kddi.so' (0x40000) is already occupied
2 [main] ruby 14188 child_info_fork::abort: address space needed by 'emoji_iso2022_kddi.so' (0x40000) is already occupied
Finished tests in 43.540324s, 0.0000 tests/s, 0.0000 assertions/s.
0 tests, 0 assertions, 0 failures, 0 errors, 0 skips
Interrupted
</code></pre>
<p>This can go on and on until I interrupt it with Ctrl-C, as done above. The errors happen in the following files:</p>
<pre><code>test/ruby/test_m17n.rb
test/ruby/test_string.rb
test/ruby/test_regexp.rb
</code></pre>
<p>although running just <code>test/ruby/test_string.rb</code> or <code>test/ruby/test_regexp.rb</code> alone works fine, but running <code>test/ruby/test_m17n.rb</code>, even if alone, produces the errors.</p>
<p>The numbers at the start of the error messages are usually very low (as above), but I have seen numbers up to around 27000 also on several occasions but rarely. The file name (<code>emoji_iso2022_kddi.so</code>) and the address (0x40000) are always the same. The numbers after <code>ruby</code> (I guess they are process numbers) vary with each run, as do the numbers at the start.</p>
<p>My current guess is that these errors should not appear if the various <code>.so</code> files are really relocatable, but I'm no expert in linking/loading details.</p>
<p>If there's any other way to run the tests, e.g. with some special option(s) to <code>test/runner.rb</code> or so, I'd appreciate a hint.</p> Ruby master - Bug #15315 (Open): ec_switch can still lose interruptshttps://bugs.ruby-lang.org/issues/153152018-11-18T00:50:29Znormalperson (Eric Wong)normalperson@yhbt.net
<p>ec_switch and thread switching may still lose interrupts</p>
<p>trap interrupt is OK because of r64062</p>
<p>Not OK:</p>
<ol>
<li>
<p>postponed job interrupt from MJIT worker<br>
This is trickiest to solve because it also affects thread switching,<br>
not just EC switching</p>
</li>
<li>
<p>pending interrupt is not safe but fixing ec_switch is sufficient because<br>
rb_threadptr_interrupt only targets threads, not EC.</p>
</li>
<li>
<p>timer interrupt is not critical because another interrupt will fire in 100ms</p>
</li>
</ol>
<p>Solutions:</p>
<p>moving interrupt_flag back to rb_thread_t will solve 2 and 3</p>
<ol>
<li>will remain dangerous, we need to add extra checks at thread switching<br>
because MJIT worker may get stuck if target thread stalls or dies.</li>
</ol> Ruby master - Bug #15263 (Open): [PATCH] vm_trace.c (postponed_job_register): only hit main threadhttps://bugs.ruby-lang.org/issues/152632018-10-27T23:35:33Znormalperson (Eric Wong)normalperson@yhbt.net
<pre><code>vm_trace.c (postponed_job_register): only hit main thread
Since postponed_job_register may be called in a signal handler,
only the main thread is safe to touch as other threads may
become invalid. Furthermore, the problem with trap interrupt
being lost during ec_switch [Bug #14939] also applies to the
postponed job and timer interrupts, so we need to preserve all
three interrupts in ec_switch.
Note: A minor problem is a possible crash during/after
ruby_vm_destruct if postponed jobs are registered.
The correct and performant fix would be to leak memory at exit
for `vm' and `vm->main_thread'. free(3) slows down short-lived
scripts, as does unregistering signal handlers.
* vm_trace.c (postponed_job_register): only hit main thread
* cont.c (ec_switch): preserve postponed and timer interrupt flags, too
</code></pre> Ruby master - Feature #15240 (Open): Set operations check for is_a?(Set), rather than allowing du...https://bugs.ruby-lang.org/issues/152402018-10-21T19:45:44Zivoanjo (Ivo Anjo)ivo.anjo@datadoghq.com
<p>Hello there 👋</p>
<p>Ruby's <code>Set</code>, unlike <code>Array</code> or <code>Hash</code>, cannot easily interoperate with user-created classes as several operations (<code>#==</code>, <code>#flatten</code>, <code>#flatten!</code>, <code>#intersect?</code>, <code>#disjoint?</code>, <code>#subset?</code>, <code>#proper_subset?</code>, <code>#superset?</code>, <code>#proper_superset?</code>) check that the other class <code>is_a?(Set)</code>, rather than allowing duck-typing.</p>
<p>Example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s1">'set'</span>
<span class="k">class</span> <span class="nc">MySet</span>
<span class="kp">include</span> <span class="no">Enumerable</span>
<span class="k">def</span> <span class="nf">each</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span> <span class="p">[</span><span class="ss">:my</span><span class="p">,</span> <span class="ss">:set</span><span class="p">].</span><span class="nf">each</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">size</span><span class="p">()</span> <span class="nb">to_a</span><span class="p">.</span><span class="nf">size</span> <span class="k">end</span>
<span class="k">end</span>
<span class="nb">puts</span> <span class="no">Set</span><span class="p">[</span><span class="ss">:set</span><span class="p">].</span><span class="nf">subset?</span><span class="p">(</span><span class="no">MySet</span><span class="p">.</span><span class="nf">new</span><span class="p">)</span>
<span class="o">=></span> <span class="no">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
<span class="mi">1</span><span class="p">:</span> <span class="n">from</span> <span class="n">testcase</span><span class="p">.</span><span class="nf">rb</span><span class="p">:</span><span class="mi">8</span><span class="ss">:in</span> <span class="sb">`<main>'
set.rb:292:in `</span><span class="n">subset?</span><span class="err">'</span><span class="p">:</span> <span class="n">value</span> <span class="n">must</span> <span class="n">be</span> <span class="n">a</span> <span class="n">set</span> <span class="p">(</span><span class="no">ArgumentError</span><span class="p">)</span>
</code></pre>
<p>The only way I've found of going around this issue and looking at the Ruby sources, is to fake a response to <code>is_a?</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s1">'set'</span>
<span class="k">class</span> <span class="nc">MySet</span>
<span class="kp">include</span> <span class="no">Enumerable</span>
<span class="k">def</span> <span class="nf">each</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span> <span class="p">[</span><span class="ss">:my</span><span class="p">,</span> <span class="ss">:set</span><span class="p">].</span><span class="nf">each</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">size</span><span class="p">()</span> <span class="nb">to_a</span><span class="p">.</span><span class="nf">size</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">is_a?</span><span class="p">(</span><span class="n">klass</span><span class="p">)</span> <span class="k">super</span> <span class="o">||</span> <span class="n">klass</span> <span class="o">==</span> <span class="no">Set</span> <span class="k">end</span> <span class="c1"># <== Hack! 😭</span>
<span class="k">end</span>
<span class="nb">puts</span> <span class="no">Set</span><span class="p">[</span><span class="ss">:set</span><span class="p">].</span><span class="nf">subset?</span><span class="p">(</span><span class="no">MySet</span><span class="p">.</span><span class="nf">new</span><span class="p">)</span>
<span class="o">=></span> <span class="kp">true</span>
</code></pre>
<p>This is a very ugly hack, and instead it would be nice if, instead, I could just provide a <code>to_set</code> method that <code>Set</code> could call to allow duck typing.</p>
<p>I'm willing to work on a patch to solve this (would be pretty nice to do my first contribution to Ruby core!), so hopefully we can discuss how this problem can be tackled.</p>
<hr>
<a name="Background-TLDR"></a>
<h3 >Background / TL;DR<a href="#Background-TLDR" class="wiki-anchor">¶</a></h3>
<p>This issue came about as I am the creator of a gem called <a href="https://gitlab.com/ivoanjo/persistent-dmnd/" class="external">persistent-💎</a>. This gem provides immutable arrays, hashes and sets. Most of the hard work is delegated to another gem (<a href="https://github.com/hamstergem/hamster" class="external">hamster</a>), but I've added a number of tweaks to allow the persistent-💎 variants to easily interoperate with their Ruby counterparts.</p>
<p>Because I wanted to allow <code>Persistent💎::Set</code> instances to be used together with Ruby's <code>Set</code>, I studied the <code>set.rb</code> implementation and came up with the <code>is_a?(Set)</code> hack above. This works on all Ruby versions the gem supports (1.9->2.6), but broke on JRuby 9.2 when a new optimized <code>Set</code> implementation was added, that did not do the <code>is_a?(Set)</code> check and thus broke the hack.</p>
<p>I've brought up this issue with the JRuby developers -- <a href="https://github.com/jruby/jruby/issues/5227" class="external">https://github.com/jruby/jruby/issues/5227</a> -- and from there we moved the discussion to ruby/spec -- <a href="https://github.com/ruby/spec/pull/629" class="external">https://github.com/ruby/spec/pull/629</a>.</p>
<p>We ended up concluding that it would make sense to raise this on the Ruby tracker as something that should be fixed on <code>Set</code> itself, rather than codifying this hack as something that Ruby is expected to support.</p>
<p>Since Ruby sets already support an implicit conversion method -- <code>to_set</code> -- it seems natural to replace the <code>is_a?(Set)</code> with some kind of <code>other.respond_to?(:to_set) && other = other.to_set</code> in all places where the <code>is_a?(Set)</code> was being used. Note that his would be all that's needed to be able to use a <code>Set</code> duck-type --- the <a href="https://gitlab.com/ivoanjo/persistent-dmnd/blob/master/spec/unit/set_spec.rb" class="external"><code>Persistent💎::Set</code> specs</a> are a pretty good proof of it.</p>
<p>Thanks for the time 🙏, and rock on 💪!</p> Ruby master - Bug #15097 (Open): Gem install fails on Ruby 2.5.1 with Cygwin (get_dns_server_list...https://bugs.ruby-lang.org/issues/150972018-09-10T03:52:01Zcaspercg (Casper G)
<p>Compiled and installed Ruby 2.5.1 on Cygwin, and now gem install fails with:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">ERROR</span><span class="p">:</span> <span class="no">While</span> <span class="n">executing</span> <span class="n">gem</span> <span class="o">...</span> <span class="p">(</span><span class="no">NameError</span><span class="p">)</span>
<span class="n">undefined</span> <span class="n">local</span> <span class="n">variable</span> <span class="ow">or</span> <span class="nb">method</span> <span class="sb">`get_dns_server_list' for Win32::Resolv:Module
</span></code></pre>
<p>While building Ruby I got the following warning:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">win32</span><span class="o">/</span><span class="ss">resolv:
</span><span class="no">Could</span> <span class="ow">not</span> <span class="n">be</span> <span class="n">configured</span><span class="o">.</span> <span class="no">It</span> <span class="n">will</span> <span class="ow">not</span> <span class="n">be</span> <span class="n">installed</span><span class="o">.</span>
<span class="no">Check</span> <span class="n">ext</span><span class="o">/</span><span class="n">win32</span><span class="o">/</span><span class="n">resolv</span><span class="o">/</span><span class="n">mkmf</span><span class="p">.</span><span class="nf">log</span> <span class="k">for</span> <span class="n">more</span> <span class="n">details</span><span class="o">.</span>
</code></pre>
<p>The error in mkmf.log is:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="sr">/ruby-2.5.1/ex</span><span class="n">t</span><span class="o">/</span><span class="n">win32</span><span class="o">/</span><span class="n">resolv</span><span class="o">/</span><span class="n">conftest</span><span class="p">.</span><span class="nf">c</span><span class="p">:</span><span class="mi">14</span><span class="p">:</span> <span class="n">undefined</span> <span class="n">reference</span> <span class="n">to</span> <span class="sb">`GetNetworkParams'
collect2: error: ld returned 1 exit status
</span></code></pre>
<p>The mkmf.log is also attached.</p>
<p>Could not figure out how to fix this problem.<br>
Is 2.5.1 not compatible with Cygwin?</p> Ruby master - Feature #14859 (Open): [PATCH] implement Timeout in VMhttps://bugs.ruby-lang.org/issues/148592018-06-21T00:21:14Znormalperson (Eric Wong)normalperson@yhbt.net
<p>implement Timeout in VM</p>
<p>Based on the ugliness of handling partial writes with<br>
IO#write_nonblock and inability to use writev(2) effectively<br>
with write timeouts in Net::HTTP in r63587-r63589, I've<br>
decided Timeout to be the more programmer-friendly option<br>
to use and to improve it.</p>
<p>Timeout is significantly faster with this patch, and stopping<br>
the timeout before expiration (common case) is optimized to be<br>
as fast as possible. This version relies on timer-thread to<br>
provide wakeup interrupts.</p>
<p>This is a minimally intrusive patch. I also started working on<br>
a more intrusive patch to touch all sleep/waiting function<br>
calls, but this is easier-to-review for now. In the future,<br>
I will try per-thread timeouts and eliminate timer-thread<br>
for platforms with POSIX timers (timer_create/timer_settime)</p>
<p>Speedup ratio: compare with the result of `trunk' (greater is better)</p>
<p>timeout_mt_nested 3.887<br>
timeout_mt_same 3.843<br>
timeout_mt_ugly 1.335<br>
timeout_nested 7.059<br>
timeout_same 5.173<br>
timeout_zero 2.587</p> Ruby master - Feature #14813 (Open): [PATCH] gc.c: make gc_enter+gc_exit pairs dtrace probes, toohttps://bugs.ruby-lang.org/issues/148132018-06-02T14:05:32Znormalperson (Eric Wong)normalperson@yhbt.net
<p>gc.c: make gc_enter+gc_exit pairs dtrace probes, too</p>
<p>I would like to use these with systemtap to gather<br>
min/max/avg/variance data for gc_*_continue functions.</p>
<p>I prefer to use systemtap/dtrace and not modify or load extra<br>
Ruby code to use built-in tracing. Systemtap also has aggregate<br>
functionality built in for @min/@max/@avg and @hist_log for<br>
generating histograms:</p>
<p><a href="https://80x24.org/spew/20180602135820.6686-1-e@80x24.org/raw" class="external">https://80x24.org/spew/20180602135820.6686-1-e@80x24.org/raw</a><br>
(work-in-progress)</p>
<p>I will add documentation to probes.d and doc/dtrace_probes.rdoc<br>
if accepted.</p> Ruby master - Bug #14640 (Open): [win32] File.realpath treats a relative path with a drive letter...https://bugs.ruby-lang.org/issues/146402018-03-28T16:18:34Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<p>When <code>t</code> exists in the current directory under the drive C:,</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">File</span><span class="p">.</span><span class="nf">realpath</span><span class="p">(</span><span class="s2">"c:t"</span><span class="p">)</span> <span class="c1">#=> No such file or directory @ realpath_rec - c:/t (Errno::ENOENT)</span>
</code></pre>
<p>whereas <code>File.expand_path</code> returns <code>Dir.pwd + "/t"</code>.</p> Ruby master - Feature #14492 (Open): iseq loading + caching should be in corehttps://bugs.ruby-lang.org/issues/144922018-02-19T04:14:35Znormalperson (Eric Wong)normalperson@yhbt.net
<pre><code>... And not in a RubyGem like yomikomu(*)
RubyGems itself is responsible for over 100ms of startup time on my system(**),
so it would be beneficial to make it part of core and speed up rubygems (and stdlib).
$ time ruby -e exit
real 0m0.160s
user 0m0.155s
sys 0m0.004s
$ time ruby --disable=gems -e exit
real 0m0.014s
user 0m0.013s
sys 0m0.000s
(*) git clone https://github.com/ko1/yomikomu.git
(**) I admit, I am intent on continuing use of Ruby on a laptop from 2005.
That's roughly when I started using Ruby, so any hardware which Ruby
worked well on back then should work equally well for current and future
versions of Ruby.
And maybe this summer I'll dig out a 600 MHz Duron from the early 2000s :D
</code></pre> Ruby master - Feature #14394 (Open): Class.descendantshttps://bugs.ruby-lang.org/issues/143942018-01-24T19:07:55Zridiculous (Ryan Buckley)arebuckley@gmail.com
<p>There have been numerous implementations of the method Class.descendants by various gems. However, I can't help but think that this ability should be included in the Ruby language itself. Especially since Ruby already offers the counterpart method Class.ancestors.</p>
<p>Would it possible to add a <code>descendants</code> class method?</p> Ruby master - Feature #13697 (Open): [PATCH]: futex based thread primitiveshttps://bugs.ruby-lang.org/issues/136972017-06-29T03:26:58Znormalperson (Eric Wong)normalperson@yhbt.net
<p>Assigning to kosaki since he wrote the current GVL.<br>
I'm hoping single-core vm_thread_pass benchmark can be<br>
improved, but I'm not sure...</p>
<pre><code>Using bare, Linux-specific futexes instead of relying on
NPTL-provided primitives seems to offer some speedups
in the more realistic benchmarks which release GVL
for IO.
Performance seems stable between multi-core and single-core
benchmarks. However, there is still more regressions for
single-core systems, but I think it mainly affects esoteric
cases. Mainly, the io_pipe_rw and vm_thread_pipe benchmarks
are improved across the board, so I am pretty happy
with that.
Some of the performance changes (good or bad) may also
be the result of size reductions between the 40-byte NPTL
mutex and the 4 byte futex shifting data into a different
cache line.
io and thread '-p (_io_|thread)' benchmark results on an
AMD FX-8320 @ 3.5GHz:
io_copy_stream_write 1.040
io_copy_stream_write_socket 1.027
io_file_create 1.016
io_file_read 1.057
io_file_write 1.001
io_nonblock_noex 1.047
io_nonblock_noex2 1.037
io_pipe_rw 1.077
io_select 1.024
io_select2 1.003
io_select3 0.991
require_thread 8.379
vm_thread_alive_check1 1.171
vm_thread_close 1.015
vm_thread_condvar1 0.979
vm_thread_condvar2 1.192
vm_thread_create_join 1.043
vm_thread_mutex1 0.985
vm_thread_mutex2 1.005
vm_thread_mutex3 0.991
vm_thread_pass 4.563
vm_thread_pass_flood 0.991
vm_thread_pipe 1.867
vm_thread_queue 0.995
vm_thread_sized_queue 1.050
vm_thread_sized_queue2 1.079
vm_thread_sized_queue3 1.073
vm_thread_sized_queue4 1.087
single core (schedtool -a 0x1 -e ...):
io_copy_stream_write 1.039
io_copy_stream_write_socket 1.012
io_file_create 1.010
io_file_read 1.066
io_file_write 0.999
io_nonblock_noex 1.061
io_nonblock_noex2 1.020
io_pipe_rw 1.101
io_select 1.008
io_select2 1.001
io_select3 0.992
require_thread 1.005
vm_thread_alive_check1 0.938
vm_thread_close 1.135
vm_thread_condvar1 1.145
vm_thread_condvar2 1.134
vm_thread_create_join 1.146
vm_thread_mutex1 0.999
vm_thread_mutex2 0.999
vm_thread_mutex3 1.001
vm_thread_pass 0.887
vm_thread_pass_flood 0.973
vm_thread_pipe 1.100
vm_thread_queue 1.013
vm_thread_sized_queue 1.125
vm_thread_sized_queue2 1.172
vm_thread_sized_queue3 1.184
vm_thread_sized_queue4 1.081
</code></pre> Ruby master - Feature #13696 (Open): Add exchange and noreplace options to File.renamehttps://bugs.ruby-lang.org/issues/136962017-06-29T03:07:38ZGlass_saga (Masaki Matsushita)glass.saga@gmail.com
<p>renameat2(2) introduced in linux kernel 3.15 takes following flags.</p>
<pre><code>RENAME_EXCHANGE: Atomically exchange oldpath and newpath.
RENAME_NOREPLACE: Don't overwrite newpath of the rename. Return an error if newpath already exists.
</code></pre>
<p>This change makes <code>File.rename</code> take these flags as keyword arguments.</p>
<p>Example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">File</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="s2">"hoge"</span><span class="p">,</span> <span class="s2">"hoge"</span><span class="p">)</span>
<span class="no">File</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="s2">"fuga"</span><span class="p">,</span> <span class="s2">"fuga"</span><span class="p">)</span>
<span class="no">File</span><span class="p">.</span><span class="nf">rename</span><span class="p">(</span><span class="s2">"hoge"</span><span class="p">,</span> <span class="s2">"fuga"</span><span class="p">,</span> <span class="ss">exchange: </span><span class="kp">true</span><span class="p">)</span> <span class="c1"># atomically exchanged</span>
<span class="no">File</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="s2">"fuga"</span><span class="p">)</span> <span class="c1">#=> "hoge"</span>
<span class="no">File</span><span class="p">.</span><span class="nf">rename</span><span class="p">(</span><span class="s2">"hoge"</span><span class="p">,</span> <span class="s2">"fuga"</span><span class="p">,</span> <span class="ss">noreplace: </span><span class="kp">true</span><span class="p">)</span> <span class="c1">#=> File exists @ syserr_fail2_in - fuga (Errno::EEXIST)</span>
</code></pre> Ruby master - Feature #13512 (Open): System Threadshttps://bugs.ruby-lang.org/issues/135122017-04-26T14:16:44Zmagaudet (Matthew Gaudet)
<p>In this feature I propose creating a VM implementation feature called (for lack of a better name) <em>System Threads</em>.</p>
<a name="Background"></a>
<h1 >Background<a href="#Background" class="wiki-anchor">¶</a></h1>
<p>I am working on adding asynchronous compilation to <a href="https://github.com/rubyomr-preview/ruby/" class="external">Ruby+OMR</a> allow compilation of methods to occur off the application thread, to avoid latency jumps when a method is selected for compilation. In the process of compiling Ruby, I really need to be able to call into the interpreter, to query for information about methods, and eventually I may even want to run small pieces of Ruby code (to fold constantes for example). I cannot call into the interpeter in any way without using a ruby level thread (required to acquire the GVL), and so, today, my implementation uses the existing Ruby thread API (<code>rb_thread_create</code>, <code>rb_thread_call_without_gvl2</code>, <code>rb_thread_call_with_gvl</code>). This approach largely works, and I am able to boot Discourse with the JIT + Async compilation enabled, thanks to <a href="https://bugs.ruby-lang.org/issues/13486" class="external">ko1</a>.</p>
<p>Unfortunately, I'm unable to pass <code>make test</code>, a curious situation.</p>
<p>The issue is that because the compilation is a persistent <code>Thread</code>, there is some functionality that stops working (though, not enough to cause Discourse to fail). For example, the deadlock detection code tested by the following case no longer fires, and so a hang occurs:</p>
<pre><code>assert_equal 'ok', %q{
begin
Thread.new { Thread.stop }
Thread.stop
:ng
rescue Exception
:ok
end
}
</code></pre>
<p>This seems undesirable: The deadlock detection API is very useful, and I really don't want to neuter it by introducing a compilation thread. Hence the proposal for a System Thread.</p>
<a name="System-Threads"></a>
<h1 >System Threads<a href="#System-Threads" class="wiki-anchor">¶</a></h1>
<p>I am proposing resolving the problem above by adding a new thread API: <code>VALUE rb_system_thread_create(VALUE (*)(ANYARGS), void*);</code>. Later extensions could provide a subclass of <code>Thread</code> called <code>SystemThread</code> however for now I consider that mildly out of scope.</p>
<p>Here are the distinguishing features as I see them:</p>
<ul>
<li>A Thread created through the System Thread API would not show up in <code>Thread::list</code> (though, if SystemThread is created, would show up in its list).</li>
<li>For the purposes of error reporting, System Threads would be resumed not to be partaking in user code. ie:
<ul>
<li>System threads aren't eligible to wake condition variables</li>
<li>System threads aren't enough to have the system able to make forward progresss.</li>
</ul>
</li>
</ul>
<a name="Potential-Users"></a>
<h2 >Potential Users:<a href="#Potential-Users" class="wiki-anchor">¶</a></h2>
<p>In addition to JIT compilation threads, I see potential for other future consumers:</p>
<ul>
<li>Concurrent garbage collection would likely need to take place on a System Thread to allow finalizers to run.</li>
<li>(Potential for misuse) one could imagine some libraries would want system threads.</li>
</ul>
<a name="Other-notes"></a>
<h1 >Other notes:<a href="#Other-notes" class="wiki-anchor">¶</a></h1>
<p>I took a little bit of time to try to implement System Threads, enough to realize that this wouldn't be a trivial implementation. There are a couple of different approaches I think that could be successful, but I didn't get deep enough into the thread code to have a strong intuition, and so I wanted to get feedback before going too far down this road.</p>
<p>As a side note, I also attempted an alternative to System Threads for the purposes of the compilation thread: I used a native thread, then intended to spawn a Ruby thread only at the point where the JIT had a query:</p>
<pre><code># This was implemented using the C-API.
def call_into_vm(query, arg)
Thread.new { query(arg) }.value
end
</code></pre>
<p>This was unsuccessful because creating a thread requires holding the GVL, but a native thread cannot acquire the GVL as near as I can tell.</p> Ruby master - Feature #13385 (Open): [PATCH] Make Resolv::DNS::Name validation similar to host an...https://bugs.ruby-lang.org/issues/133852017-03-29T09:17:33Zpavel.mikhailyuk@gmail.com (Pavel Mikhailyuk)
<a name="Abstract"></a>
<h1 >Abstract<a href="#Abstract" class="wiki-anchor">¶</a></h1>
<p>Add validations similar to <strong>host</strong> and <strong>dig</strong> commands to <code>Resolv::DNS::Name.create</code></p>
<a name="Background"></a>
<h1 >Background<a href="#Background" class="wiki-anchor">¶</a></h1>
<p><code>Resolv::DNS::Name.create(str)</code> does not make any domain name validation.<br>
So it returns false positive results for queries like</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">></span> <span class="no">Resolv</span><span class="o">::</span><span class="no">DNS</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">getresources</span><span class="p">(</span><span class="s1">'.gmail....com'</span><span class="p">,</span> <span class="no">Resolv</span><span class="o">::</span><span class="no">DNS</span><span class="o">::</span><span class="no">Resource</span><span class="o">::</span><span class="no">IN</span><span class="o">::</span><span class="no">MX</span><span class="p">)</span>
<span class="o">=></span> <span class="p">[</span><span class="c1">#<Resolv::DNS::Resource::IN::MX:0x007fc3107ecf68 @exchange=#<Resolv::DNS::Name: alt1.gmail-smtp-in.l.google.com.>, @preference=10, @ttl=3600>,</span>
<span class="c1">#<Resolv::DNS::Resource::IN::MX:0x007fc313013730 @exchange=#<Resolv::DNS::Name: alt2.gmail-smtp-in.l.google.com.>, @preference=20, @ttl=3600>,</span>
<span class="c1">#<Resolv::DNS::Resource::IN::MX:0x007fc313011f20 @exchange=#<Resolv::DNS::Name: gmail-smtp-in.l.google.com.>, @preference=5, @ttl=3600>,</span>
<span class="c1">#<Resolv::DNS::Resource::IN::MX:0x007fc313010a30 @exchange=#<Resolv::DNS::Name: alt4.gmail-smtp-in.l.google.com.>, @preference=40, @ttl=3600>,</span>
<span class="c1">#<Resolv::DNS::Resource::IN::MX:0x007fc313012858 @exchange=#<Resolv::DNS::Name: alt3.gmail-smtp-in.l.google.com.>, @preference=30, @ttl=3600>]</span>
</code></pre>
<p>while</p>
<pre><code class="text syntaxhl" data-language="text">~ dig .gmail....com MX
dig: '.gmail....com' is not a legal name (empty label)
</code></pre>
<p>I added basic RFC validations in <code>Resolv::DNS::Label.split</code> to get <code>ArgumentError</code> with messages similar to <strong>host</strong> and <strong>dig</strong> commands.</p>
<a name="Pull-request"></a>
<h1 >Pull request<a href="#Pull-request" class="wiki-anchor">¶</a></h1>
<p><a href="https://github.com/ruby/ruby/pull/1551" class="external">https://github.com/ruby/ruby/pull/1551</a></p> Ruby master - Bug #11840 (Open): Error with "make check" on Cygwinhttps://bugs.ruby-lang.org/issues/118402015-12-18T05:54:23Zduerst (Martin Dürst)duerst@it.aoyama.ac.jp
<p>Encouraged by Hiroshi Shibata's talk at Ruby Kaigi 2015, I tried "make check" on my usual cygwin compilation. If I understand the output below correctly, there was only one error in 1010 tests. If we can fix that error (or exclude the test if it doesn't make sense on cygwin or on Windows in general), then cygwin would pass the tests.</p>
<pre><code>generating prelude.c
prelude.c unchanged
make[2]: 'rubyw.exe' is up to date.
make[2]: Leaving directory '/cygdrive/c/Data/ruby-public'
make[1]: Leaving directory '/cygdrive/c/Data/ruby-public'
test succeeded
#254 test_fork.rb: F
begin
r, w = IO.pipe
if pid1 = fork
w.close
r.read(1)
Process.kill("USR1", pid1)
_, s = Process.wait2(pid1)
s.success? ? :ok : :ng
else
r.close
if pid2 = fork
trap("USR1") { Time.now.to_s; Process.kill("USR2", pid2) }
w.close
Process.wait2(pid2)
else
w.close
sleep 0.2
end
exit true
end
rescue NotImplementedError
:ok
end
#=> "ng" (expected "ok") <a href="/issues/3005">[ruby-core:28924]</a>
stderr output is not empty
bootstraptest.tmp.rb:13:in `kill': No such process (Errno::ESRCH)
from bootstraptest.tmp.rb:13:in `block in <main>'
from bootstraptest.tmp.rb:15:in `wait2'
from bootstraptest.tmp.rb:15:in `<main>'
test_fork.rb FAIL 1/5
FAIL 1/1010 tests failed
uncommon.mk:581: recipe for target 'yes-btest-ruby' failed
make: *** [yes-btest-ruby] Error 1
</code></pre> Ruby master - Bug #11808 (Open): Different behavior between Enumerable#grep and Array#grephttps://bugs.ruby-lang.org/issues/118082015-12-11T23:53:02ZBenOlive (Ben Olive)ben.olive@gatech.edu
<p>Regex special global variables are available within the block for <code>Array#grep</code>, but are nil within the block for <code>Enumerable#grep</code>.</p>
<p>Here is an example that explains it better:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Test</span>
<span class="kp">include</span> <span class="no">Enumerable</span>
<span class="k">def</span> <span class="nf">each</span>
<span class="k">return</span> <span class="n">enum_for</span><span class="p">(</span><span class="ss">:each</span><span class="p">)</span> <span class="k">unless</span> <span class="nb">block_given?</span>
<span class="k">yield</span> <span class="s2">"Hello"</span>
<span class="k">yield</span> <span class="s2">"World"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">enum</span> <span class="o">=</span> <span class="no">Test</span><span class="p">.</span><span class="nf">new</span>
<span class="n">array</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"Hello"</span><span class="p">,</span> <span class="s2">"World"</span><span class="p">]</span>
<span class="n">enum</span><span class="p">.</span><span class="nf">grep</span><span class="p">(</span><span class="sr">/^(.)/</span><span class="p">)</span> <span class="p">{</span><span class="vg">$1</span><span class="p">}</span> <span class="c1"># => [nil, nil]</span>
<span class="n">array</span><span class="p">.</span><span class="nf">grep</span><span class="p">(</span><span class="sr">/^(.)/</span><span class="p">)</span> <span class="p">{</span><span class="vg">$1</span><span class="p">}</span> <span class="c1"># => ["H", "W"]</span>
</code></pre>
<p>Tested on 2.0.0, 2.1.5, & 2.2.2</p> Ruby master - Feature #11710 (Open): [PATCH] Replace Set#merge with Set#merge! and make Set#merge...https://bugs.ruby-lang.org/issues/117102015-11-18T17:16:44Ztiegz (Tieg Zaharia)tieg.zaharia@gmail.com
<p>The Set#merge method currently mutates its caller. I propose changing its behavior to non-mutating, and replace its current behavior with a mutating Set#merge! method.</p>
<p>For example, the current behavior:</p>
<pre><code>> s = Set.new [1,2,3] # => #<Set: {1, 2, 3}>
> s.object_id # => 70125370250380
> s.merge([4,5,6]) # => #<Set: {1, 2, 3, 4, 5, 6}>
> s # => #<Set: {1, 2, 3, 4, 5, 6}>
> s.object_id # => 70125370250380
</code></pre>
<p>Set describes itself as a hybrid of Array and Hash, but Hash#merge does not mutate its caller, and Set is implemented on top of Hash as well. Hash has a merge! method that can mutate instead:</p>
<pre><code>> h = {a: 1, b: 2} # => {:a=>1, :b=>2}
> h.object_id # => 70125369896320
> h.merge({c: 3}) # => {:a=>1, :b=>2, :c=>3}
> h # => {:a=>1, :b=>2}
irb(main):015:0> h.object_id # => 70125369896320
</code></pre>
<p>We were taken by surprise with the existing behavior of Set#merge, especially since Set follows the bang pattern of mutating/non-mutating method names (e.g. collect!, reject!, select!, flatten!)</p>
<p>I noticed this has been <a href="https://bugs.ruby-lang.org/issues/5185" class="external">suggested before</a>, but was hoping it might be possible as a breaking change for 2.3.0?</p> Ruby master - Bug #11438 (Open): native_thread_init_stack() get machine.stack_start unequal to th...https://bugs.ruby-lang.org/issues/114382015-08-13T07:31:10Zrickerliang (l ly)rickerliang@outlook.com
<p>In function native_thread_init_stack() use VirtualQuery to get thread's stack start address.But some situation(ruby embbed in other application and initial it on the fly),native_thread_init_stack() will be called at low stack address and VirtualQuery return memory info BaseAddress + RegionSize < thread stack base(teb.StackBase).<br>
In this situation,subsequently call stack_check() at high stack address will cause stack_overflow exception,because esp > machine.stack_start:<br>
(teb.StackLimit < machine.stack_start < esp < teb.StackBase)<br>
but actually it is not stack overflow at this time.<br>
Use teb.StackBase instead of VirtualQuery get thread stack base is a more reliable solution.</p> Ruby master - Feature #11312 (Open): Add Resolv::DNS::Resource::IN::SPFhttps://bugs.ruby-lang.org/issues/113122015-06-26T18:58:49Zpostmodern (Hal Brodigan)postmodern.mod3@gmail.com
<p>The SPF type record (RFC4408 Section 3.1.1) is quite common now. The resolv library should probably support it. As a workaround I monkey patched in the resource class:</p>
<pre><code>class Resolv::DNS::Resource::IN::SPF < Resolv::DNS::Resource::IN::TXT
# resolv.rb doesn't define an SPF resource type.
TypeValue = 99
ClassValue = Resolv::DNS::Resource::IN::ClassValue
Resolv::DNS::Resource::ClassHash[[TypeValue, ClassValue]] = self
end
</code></pre>
<p>I could formalize my monkeypatch into an actual patch. I would just need to know whether SPF should be listed in the <code>ClassInsensitiveTypes</code> array.</p> Ruby master - Feature #10932 (Open): Enabling allocation tracing as early as possiblehttps://bugs.ruby-lang.org/issues/109322015-03-03T19:53:30Ztenderlovemaking (Aaron Patterson)tenderlove@ruby-lang.org
<p>Hi,</p>
<p>I'd like to be able to enable allocation tracing as early as possible. I've attached a patch that I use to do that when I'm debugging code that I don't know very well.</p>
<p>The way I use it is like this:</p>
<p>$ ruby -robjspace/trace_start some_test.rb</p>
<p>I like using this because many times I can't figure out when to enable object tracing. Can we add this feature to object space?</p> Ruby master - Feature #10423 (Open): [PATCH] opt_str_lit*: avoid literal string allocationshttps://bugs.ruby-lang.org/issues/104232014-10-24T03:25:32Znormalperson (Eric Wong)normalperson@yhbt.net
<p>Patch also downloadable at: <a href="http://80x24.org/spew/m/opt_str_lit-v4%40m.txt" class="external">http://80x24.org/spew/m/opt_str_lit-v4%40m.txt</a><br>
Broken-out commits in the "opt_str_lit-v4" branch of<br>
git://bogomips.org/ruby.git (and <a href="http://bogomips.org/ruby.git" class="external">http://bogomips.org/ruby.git</a> )</p>
<p>This obsoletes Features <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: [PATCH] optimize: recv << "literal string" (Rejected)" href="https://bugs.ruby-lang.org/issues/10326">#10326</a>, <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: [PATCH 2/1] optimize: foo == "literal string" (Rejected)" href="https://bugs.ruby-lang.org/issues/10329">#10329</a>, and <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: [PATCH 3/1] optimize: "yoda literal" == string (Rejected)" href="https://bugs.ruby-lang.org/issues/10333">#10333</a></p>
<p>Changes since -v3</p>
<ul>
<li>
<p>cleanup tests to be more DRY</p>
</li>
<li>
<p>optimize allocations for Hash#fetch, String#r?partition</p>
</li>
<li>
<p>split opt_str_lit into 3 instructions to reduce insn complexity<br>
(opt_str_freeze, opt_aset_with, opt_aref_with) are still gone.</p>
<p>While having one instruction is appealing in some ways,<br>
hiding compile-time-resolvable branches behind it is<br>
misleading and it should be easier-to-follow when divided<br>
into three methods.</p>
<ol>
<li>
<p>opt_str_lit_recv: for "literal string" receivers<br>
This no longer optimizes the method dispatch away<br>
for String#freeze, the method call now always happens<br>
(but allocation is avoided)</p>
</li>
<li>
<p>opt_str_lit_tmask: the most heavily-used<br>
This optimizes allocations away for "literal string" arguments</p>
</li>
<li>
<p>opt_str_lit_data: currently only used for Time#strftime<br>
We may remove this (and the strftime optimization)<br>
if it is too rare to be useful.</p>
</li>
</ol>
</li>
</ul>
<p>Benchmarks:</p>
<p>"make rdoc" performance improved from 66.3 => 63.3 sec</p>
<p>vm2_* benchmarks:</p>
<p>We take a speed hit from losing opt_aref_with/opt_aset_with<br>
but I think the flexibility of the new instructions is worth it.</p>
<p>Speedup ratio: compare with the result of `trunk' (greater is better)</p>
<pre><code>name built
loop_whileloop2 1.000
vm2_array* 0.997
vm2_array_delete_lit* 2.204
vm2_array_include_lit* 2.372
vm2_bigarray* 1.002
vm2_bighash* 1.004
vm2_case* 1.030
vm2_defined_method* 1.013
vm2_dstr* 0.977
vm2_eval* 1.019
vm2_hash_aref_lit* 0.767
vm2_hash_aset_lit* 0.828
vm2_hash_delete_lit* 2.254
vm2_method* 1.010
vm2_method_missing* 1.010
vm2_method_with_block* 0.996
vm2_mutex* 0.954
vm2_newlambda* 1.010
vm2_poly_method* 0.974
vm2_poly_method_ov* 0.990
vm2_proc* 1.003
vm2_raise1* 0.992
vm2_raise2* 0.993
vm2_regexp* 1.053
vm2_send* 1.000
vm2_set_include_lit* 1.051
vm2_str_delete* 1.365
vm2_str_eq1* 2.282
vm2_str_eq2* 2.700
vm2_str_eqq1* 2.062
vm2_str_eqq2* 2.421
vm2_str_fmt* 1.271
vm2_str_gsub_bang_lit* 1.650
vm2_str_gsub_bang_re* 1.153
vm2_str_gsub_re* 1.110
vm2_str_plus1* 1.496
vm2_str_plus2* 1.618
vm2_str_tr_bang* 1.527
vm2_strcat* 1.406
vm2_super* 1.005
vm2_unif1* 0.985
vm2_zsuper* 0.992
-----------------------------------------------------------
raw data:
[["loop_whileloop2",
[[0.09168246667832136,
0.09153273981064558,
0.09135112632066011,
0.09144351910799742,
0.0913569862022996],
[0.09150420501828194,
0.09135987050831318,
0.09148290101438761,
0.09135456290096045,
0.09141282178461552]]],
["vm2_array",
[[0.6448190519586205,
0.6377620408311486,
0.6456073289737105,
0.636782786808908,
0.64611473120749],
[0.6434593833982944,
0.6479324344545603,
0.6385641889646649,
0.6491997549310327,
0.6610294701531529]]],
["vm2_array_delete_lit",
[[0.44069126434624195,
0.43327025789767504,
0.44154794327914715,
0.43351241294294596,
0.4343419009819627],
[0.24649471696466208,
0.24813515041023493,
0.2801106022670865,
0.24796569626778364,
0.25444996636360884]]],
["vm2_array_include_lit",
[[0.42663843277841806,
0.42771619465202093,
0.4342082254588604,
0.4192065382376313,
0.4339462127536535],
[0.24434014037251472,
0.23243559524416924,
0.23569373413920403,
0.2295856410637498,
0.23521045502275229]]],
["vm2_bigarray",
[[5.9676302736625075,
5.921381871215999,
5.893002421595156,
5.898605763912201,
5.92879247572273],
[5.918988090008497,
5.953728860244155,
5.910121874883771,
5.894348439760506,
5.882020344957709]]],
["vm2_bighash",
[[3.5214368999004364,
3.5914944410324097,
3.5528544737026095,
3.6002828497439623,
3.595806434750557],
[3.6454197568818927,
3.5987599324434996,
3.631806828081608,
3.5076274275779724,
3.5060981484130025]]],
["vm2_case",
[[0.16305183991789818,
0.16213963273912668,
0.1626761993393302,
0.1703133536502719,
0.16371900774538517],
[0.1630518063902855,
0.16097174491733313,
0.16129930969327688,
0.16106242593377829,
0.16007240489125252]]],
["vm2_defined_method",
[[2.4309032559394836,
2.4551019677892327,
2.4333217879757285,
2.4307468980550766,
2.4270543046295643],
[2.3963797464966774,
2.4110122229903936,
2.592901307158172,
2.7106671230867505,
2.6869526272639632]]],
["vm2_dstr",
[[1.206045768223703,
1.1181026576086879,
1.29782950039953,
1.074333599768579,
1.060404953546822],
[1.0911998134106398,
1.3560991054400802,
1.096764899790287,
1.0906088771298528,
1.0831655990332365]]],
["vm2_eval",
[[12.45692038256675,
12.536506623961031,
12.868694677948952,
12.425183075480163,
12.422813648357987],
[12.490455374121666,
12.190652490593493,
12.194032781757414,
12.581901006400585,
13.230092607438564]]],
["vm2_hash_aref_lit",
[[0.2547442754730582,
0.25785687286406755,
0.2552897445857525,
0.2547551356256008,
0.2546374099329114],
[0.3131725639104843,
0.3109410647302866,
0.30428329203277826,
0.30984809901565313,
0.30932857654988766]]],
["vm2_hash_aset_lit",
[[0.3067243071272969,
0.307466727681458,
0.3059097733348608,
0.32101333420723677,
0.3114894386380911],
[0.3522613048553467,
0.3512485157698393,
0.3521018158644438,
0.35033643897622824,
0.35163887683302164]]],
["vm2_hash_delete_lit",
[[0.4271302009001374,
0.5321928421035409,
0.42596039827913046,
0.4215333154425025,
0.4221466425806284],
[0.2427450241521001,
0.23863658774644136,
0.23870530910789967,
0.23786015156656504,
0.24112990126013756]]],
["vm2_method",
[[1.2295677298679948,
1.2423510188236833,
1.2246184339746833,
1.213058383204043,
1.3788639837875962],
[1.2468778286129236,
1.2022472834214568,
1.319407593458891,
1.3409598469734192,
1.246872222982347]]],
["vm2_method_missing",
[[1.8783203130587935,
2.0230442117899656,
1.7176201958209276,
1.790073310956359,
1.7432779222726822],
[1.710430753417313,
1.8266426706686616,
1.7299889298155904,
1.7529844669625163,
1.7007915144786239]]],
["vm2_method_with_block",
[[1.3849838990718126,
1.345238379202783,
1.3416069420054555,
1.3473590090870857,
1.3418097402900457],
[1.3468122174963355,
2.0074896160513163,
1.3560442496091127,
1.353834005072713,
1.3525155214592814]]],
["vm2_mutex",
[[0.6452304208651185,
0.7461022492498159,
0.7083938084542751,
0.7519227871671319,
0.7953951777890325],
[0.6722144978120923,
0.6991892093792558,
0.699041954241693,
0.8469044668599963,
0.7956293905153871]]],
["vm2_newlambda",
[[0.7562470361590385,
0.7670294912531972,
0.7572819162160158,
0.8686427380889654,
0.772026221267879],
[0.7586023258045316,
0.7559101320803165,
0.7497995179146528,
0.7534453617408872,
0.7510695895180106]]],
["vm2_poly_method",
[[2.1563803972676396,
1.9838355090469122,
2.0223182002082467,
1.9927900172770023,
2.055130822584033],
[2.03470276389271,
2.187690651975572,
2.162980039604008,
2.143593772314489,
2.04829403758049]]],
["vm2_poly_method_ov",
[[0.22944753244519234,
0.2304667690768838,
0.22847569175064564,
0.22843772917985916,
0.22901444043964148],
[0.2298243623226881,
0.2334523554891348,
0.23789969086647034,
0.23442872054874897,
0.23049725405871868]]],
["vm2_proc",
[[0.46109406277537346,
0.4476210633292794,
0.44980251509696245,
0.4451689962297678,
0.4452860997989774],
[0.4545932151377201,
0.4440324120223522,
0.44979235529899597,
0.4695265833288431,
0.4635683596134186]]],
["vm2_raise1",
[[4.989030849188566,
4.951415436342359,
4.755166156217456,
4.824490828439593,
4.795467809773982],
[4.797340838238597,
4.799810292199254,
4.792353850789368,
4.966345896013081,
5.099304006434977]]],
["vm2_raise2",
[[7.062344457022846,
7.118377918377519,
7.290325260721147,
7.1321266973391175,
7.341989707201719],
[7.456813280470669,
7.130581725388765,
7.1143358228728175,
7.1227226899936795,
7.2687620194628835]]],
["vm2_regexp",
[[1.0923050865530968,
1.0876065697520971,
1.0792832653969526,
1.0728685557842255,
1.098634515888989],
[1.172722346149385,
1.0436540711671114,
1.0638451064005494,
1.0391646642237902,
1.023901374079287]]],
["vm2_send",
[[0.3253856906667352,
0.31978365778923035,
0.32439478673040867,
0.3290995704010129,
0.32464261166751385],
[0.31982277520000935,
0.32479251362383366,
0.31968420650810003,
0.3205655198544264,
0.32221281714737415]]],
["vm2_set_include_lit",
[[0.7017893251031637,
0.7203339897096157,
0.714060970582068,
0.7558876499533653,
0.7028816910460591],
[0.6870902189984918,
0.6755420127883554,
0.6719080805778503,
0.6900417571887374,
1.1408466212451458]]],
["vm2_str_delete",
[[0.671600878238678,
0.6570039531216025,
0.6776775699108839,
0.6644531870260835,
0.97628088388592],
[0.508894819766283,
0.5154125597327948,
0.5064034061506391,
0.5130562232807279,
0.5056716529652476]]],
["vm2_str_eq1",
[[0.42520802468061447,
0.42302330397069454,
0.42416366562247276,
0.4216942973434925,
0.4239108320325613],
[0.23870286531746387,
0.23699089046567678,
0.2361262608319521,
0.31979569140821695,
0.26054865028709173]]],
["vm2_str_eq2",
[[0.42534991446882486,
0.4238837053999305,
0.4327298905700445,
0.42395070381462574,
0.42501260805875063],
[0.21500772424042225,
0.21449210867285728,
0.2152256891131401,
0.21711387671530247,
0.2152888299897313]]],
["vm2_str_eqq1",
[[0.45151620265096426,
0.4597599729895592,
0.45280721783638,
0.4582480965182185,
0.45380780193954706],
[0.26729187835007906,
0.26626693457365036,
0.2660442851483822,
0.26674115750938654,
0.2721241358667612]]],
["vm2_str_eqq2",
[[0.45260279811918736,
0.44771482422947884,
0.4570333072915673,
0.5335573730990291,
0.4592890217900276],
[0.2385527715086937,
0.24223692156374454,
0.24510123394429684,
0.2744274791330099,
0.2447566892951727]]],
["vm2_str_fmt",
[[2.614012835547328,
2.6062369514256716,
2.5333361653611064,
2.50343619287014,
2.641179056838155],
[1.9900542199611664,
2.0983974151313305,
1.9898552373051643,
2.001521130092442,
1.9963106652721763]]],
["vm2_str_gsub_bang_lit",
[[1.1346126468852162,
1.134159336797893,
1.1467241132631898,
1.170719631947577,
1.149439207278192],
[0.737271074205637,
0.7308303005993366,
0.730314377695322,
0.7260715514421463,
0.7231733025982976]]],
["vm2_str_gsub_bang_re",
[[1.4583028750494123,
1.4592840988188982,
1.4590299287810922,
1.4751051738858223,
1.492074583657086],
[1.3006651625037193,
1.3510901927947998,
1.2767879888415337,
1.3884455161169171,
1.277703725732863]]],
["vm2_str_gsub_re",
[[1.7273316802456975,
1.7103399503976107,
1.7015334982424974,
1.690703290514648,
1.694624281488359],
[1.5322920577600598,
1.5391994584351778,
1.5388264516368508,
1.5372542077675462,
1.5352015374228358]]],
["vm2_str_plus1",
[[0.653569158166647,
0.6917095249518752,
0.6521412674337626,
0.6697740163654089,
0.7296328162774444],
[0.46872936747968197,
0.48235206957906485,
0.46762560587376356,
0.4766495209187269,
0.4661587802693248]]],
["vm2_str_plus2",
[[0.6671840893104672,
0.6488652648404241,
0.6509246686473489,
0.6638444662094116,
0.6557880509644747],
[0.43602617271244526,
0.4365514535456896,
0.45153723005205393,
0.437131704762578,
0.44073084741830826]]],
["vm2_str_tr_bang",
[[2.6861952347680926,
2.816385295242071,
2.919709806330502,
2.712329135276377,
2.6914397440850735],
[1.79120559617877,
1.8011440439149737,
1.7935738116502762,
1.7961191991344094,
1.794896787032485]]],
["vm2_strcat",
[[0.7171547841280699,
0.7207952421158552,
0.7209635498002172,
0.7520132083445787,
0.7179927034303546],
[0.5424934774637222,
0.5365820089355111,
0.5409346511587501,
0.5369464093819261,
0.5396620389074087]]],
["vm2_super",
[[0.43017072789371014,
0.4671447016298771,
0.43235956504940987,
0.43128165043890476,
0.4320727000012994],
[0.42843823600560427,
0.4359660716727376,
0.46027328819036484,
0.43320534005761147,
0.4283680962398648]]],
["vm2_unif1",
[[0.22890623100101948,
0.23932419251650572,
0.2282293662428856,
0.2281231889501214,
0.22829711250960827],
[0.23160281032323837,
0.23210297524929047,
0.23051423579454422,
0.23075581435114145,
0.2301806192845106]]],
["vm2_zsuper",
[[0.44561540707945824,
0.4586751004680991,
0.468279717490077,
0.44244454242289066,
0.4582256320863962],
[0.5099742524325848,
0.44541092310100794,
0.4480971107259393,
0.4709290647879243,
0.5650665555149317]]]]
Elapsed time: 646.078768307 (sec)
-----------------------------------------------------------
benchmark results:
minimum results in each 5 measurements.
Execution time (sec)
name trunk built
loop_whileloop2 0.091 0.091
vm2_array* 0.545 0.547
vm2_array_delete_lit* 0.342 0.155
vm2_array_include_lit* 0.328 0.138
vm2_bigarray* 5.802 5.791
vm2_bighash* 3.430 3.415
vm2_case* 0.071 0.069
vm2_defined_method* 2.336 2.305
vm2_dstr* 0.969 0.992
vm2_eval* 12.331 12.099
vm2_hash_aref_lit* 0.163 0.213
vm2_hash_aset_lit* 0.215 0.259
vm2_hash_delete_lit* 0.330 0.147
vm2_method* 1.122 1.111
vm2_method_missing* 1.626 1.609
vm2_method_with_block* 1.250 1.255
vm2_mutex* 0.554 0.581
vm2_newlambda* 0.665 0.658
vm2_poly_method* 1.892 1.943
vm2_poly_method_ov* 0.137 0.138
vm2_proc* 0.354 0.353
vm2_raise1* 4.664 4.701
vm2_raise2* 6.971 7.023
vm2_regexp* 0.982 0.933
vm2_send* 0.228 0.228
vm2_set_include_lit* 0.610 0.581
vm2_str_delete* 0.566 0.414
vm2_str_eq1* 0.330 0.145
vm2_str_eq2* 0.333 0.123
vm2_str_eqq1* 0.360 0.175
vm2_str_eqq2* 0.356 0.147
vm2_str_fmt* 2.412 1.899
vm2_str_gsub_bang_lit* 1.043 0.632
vm2_str_gsub_bang_re* 1.367 1.185
vm2_str_gsub_re* 1.599 1.441
vm2_str_plus1* 0.561 0.375
vm2_str_plus2* 0.558 0.345
vm2_str_tr_bang* 2.595 1.700
vm2_strcat* 0.626 0.445
vm2_super* 0.339 0.337
vm2_unif1* 0.137 0.139
vm2_zsuper* 0.351 0.354
---
benchmark/bm_vm2_array_delete_lit.rb | 6 +
benchmark/bm_vm2_array_include_lit.rb | 6 +
benchmark/bm_vm2_hash_aref_lit.rb | 6 +
benchmark/bm_vm2_hash_aset_lit.rb | 6 +
benchmark/bm_vm2_hash_delete_lit.rb | 6 +
benchmark/bm_vm2_set_include_lit.rb | 7 +
benchmark/bm_vm2_str_delete.rb | 6 +
benchmark/bm_vm2_str_eq1.rb | 6 +
benchmark/bm_vm2_str_eq2.rb | 6 +
benchmark/bm_vm2_str_eqq1.rb | 6 +
benchmark/bm_vm2_str_eqq2.rb | 6 +
benchmark/bm_vm2_str_fmt.rb | 5 +
benchmark/bm_vm2_str_gsub_bang_lit.rb | 6 +
benchmark/bm_vm2_str_gsub_bang_re.rb | 6 +
benchmark/bm_vm2_str_gsub_re.rb | 6 +
benchmark/bm_vm2_str_plus1.rb | 6 +
benchmark/bm_vm2_str_plus2.rb | 6 +
benchmark/bm_vm2_str_tr_bang.rb | 7 +
benchmark/bm_vm2_strcat.rb | 7 +
common.mk | 18 +-
compile.c | 330 ++++++++++++++++++++++++++++++----
defs/id.def | 38 ++++
defs/opt_method.def | 90 ++++++++++
insns.def | 275 ++++++++++++++++------------
template/opt_method.h.tmpl | 111 ++++++++++++
template/opt_method.inc.tmpl | 42 +++++
test/-ext-/symbol/test_type.rb | 1 +
test/objspace/test_objspace.rb | 1 +
test/ruby/envutil.rb | 20 +++
test/ruby/test_hash.rb | 2 +
test/ruby/test_iseq.rb | 1 +
test/ruby/test_optimization.rb | 162 ++++++++++++++++-
vm.c | 67 +------
vm_core.h | 44 +----
vm_insnhelper.c | 8 +-
vm_insnhelper.h | 27 +++
36 files changed, 1089 insertions(+), 264 deletions(-)
</code></pre> Ruby master - Feature #10238 (Open): todo: remove dependency on malloc_usable_sizehttps://bugs.ruby-lang.org/issues/102382014-09-14T00:16:28Znormalperson (Eric Wong)normalperson@yhbt.net
<p>malloc_usable_size shows up at or near the top of many profiles for me.</p>
<p>We should be able to use ruby_sized_xfree in more places; especially<br>
if rb_data_type_t->dsize is defined.</p>
<p>One possible improvement is to allow the rb_data_type_t->dsize pointer<br>
to be a FIXNUM, removing the need for some memsize functions.</p>
<p>Furthermore, over-accounting malloc-ed bytes (presumably the reason<br>
malloc_usable_size was introduced). should be less harmful nowadays with<br>
incremental marking.</p> Ruby master - Bug #10128 (Open): Quoting problem for arguments of Kernel.system, Kernel.exec on W...https://bugs.ruby-lang.org/issues/101282014-08-12T16:18:30ZMaxLap (Maxime Lapointe)hunter_spawn@hotmail.com
<p>On Windows, the methods that call shell commands and receive the parameters individually sometimes do not wrap the parameters sent in quotes.<br>
This results in Windows either splitting the parameter in 2 parameters or, worse, splitting the command in 2 commands.</p>
<p>I joined the file <em>puts_first.bat</em>, which simply outputs the first argument it received. When the parameter received was wrapped by ruby, you will see quotes, it's normal. Just run a irb from from the directory containing that file.</p>
<p>Lines that don't work properly (Using Kernel.exec will do the same thing):</p>
<pre><code># these write *hello*, then says 'world' is not recognized as an internal or external command
Kernel.system 'puts_first.bat', 'hello&world'
Kernel.system 'puts_first.bat', 'hello|world'
# these write *hello*
Kernel.system 'puts_first.bat', 'hello,world'
Kernel.system 'puts_first.bat', 'hello;world'
Kernel.system 'puts_first.bat', 'hello<world'
# this writes *hello* in the file world
Kernel.system 'puts_first.bat', 'hello>world'
# this writes *helloworld* without the ^
Kernel.system 'puts_first.bat', 'hello^world'
</code></pre>
<p>If we add a space anywhere in the above hello world strings, it will work as expected because ruby wraps the parameter if it finds a space.</p>
<pre><code># Ruby does try to wrap if it finds a double quote, but it escapes double quotes incorrectly:
# this writes *"hello\"world"*, double quotes should be escaped by putting 2 of them, so we should see: *"hello""world"*
Kernel.system 'puts_first.bat', 'hello"world'
# adding a space show the problem in action, this writes *"hello\"*
Kernel.system 'puts_first.bat', 'hello" world'
</code></pre>
<p>As a side note, the single quote is not special in Windows, so there is no need to wrap this (but I don't think it's a problem):</p>
<pre><code># this writes *"hello'world"*
Kernel.system 'puts_first.bat', "hello'world"
</code></pre>
<p>This bug also happens in 1.9.3, do you think this be backported?</p>
<p>Unless I did a mistake, this should be all of the problematic characters, I tested with every printable ascii characters.</p>
<p>Thank you</p> Ruby master - Bug #10009 (Open): IO operation is 10x slower in multi-thread environmenthttps://bugs.ruby-lang.org/issues/100092014-07-06T07:35:01Zariveira (Alexandre Riveira)alexandre@objectdata.com.br
<p>I created this issue <a class="issue tracker-5 status-1 priority-4 priority-default" title="Misc: better concurrency in threads (Open)" href="https://bugs.ruby-lang.org/issues/9832">#9832</a> but not have io operation.<br>
In the script attached I simulate IO operation in multi-thread environment.<br>
For ruby 1.9.2 apply <code>taskset -c -p 2 #{Process.pid}</code> for regulates threads behavior.<br>
The second Thread is a io operation</p>
<p>My results:</p>
<ol>
<li>
<p>ruby 2.1.2<br>
first 43500194<br>
second 95<br>
third 42184385</p>
</li>
<li>
<p>ruby-2.0.0-p451<br>
first 38418401<br>
second 95<br>
third 37444470</p>
</li>
<li>
<p>1.9.3-p545<br>
first 121260313<br>
second 50<br>
third 44275164</p>
</li>
<li>
<p>1.9.2-p320<br>
first 31189901<br>
second 897 <============<br>
third 31190598</p>
</li>
</ol>
<p>Regards</p>
<p>Alexandre Riveira</p> Ruby master - Bug #9409 (Open): Cygwin で "filesystem" の encoding が正しくないケースhttps://bugs.ruby-lang.org/issues/94092014-01-14T08:43:25Zganaware (Nayuta Taga)
<p>Cygwin で環境変数 LANG に設定されているエンコーディングと<br>
システムのコードページが異なる場合<br>
"filesystem" の encoding が正しく設定されないようです。</p>
<p>例えば、</p>
<ul>
<li>Windows 7 (日本語)</li>
<li>Cygwin 環境 (CYGWIN_NT-6.1-WOW64 ****** 1.7.27(0.271/5/3) 2013-12-09 11:57 i686 Cygwin)</li>
<li>環境変数 LANG は ja_JP.UTF-8</li>
<li>カレントディレクトリに「<code>日本語.txt</code>」という名前のファイルが存在</li>
</ul>
<p>という状態で以下のコードを実行すると</p>
<pre><code>print "LANG=#{ENV['LANG']}\n"
print "\n"
Dir.open('.').each{|item|
p item.encoding
p item
}
print "\n"
Dir.open('.',encoding: 'locale').each{|item|
p item.encoding
p item
}
print "\n"
</code></pre>
<p>例えば以下のような出力が得られます。</p>
<pre><code>LANG=ja_JP.UTF-8
#<Encoding:Windows-31J>
"."
#<Encoding:Windows-31J>
".."
#<Encoding:Windows-31J>
"test.rb"
#<Encoding:Windows-31J>
"\x{E697}\xA5\x{E69C}\xAC\x{E8AA}\x9E.txt"
#<Encoding:UTF-8>
"."
#<Encoding:UTF-8>
".."
#<Encoding:UTF-8>
"test.rb"
#<Encoding:UTF-8>
"日本語.txt"
</code></pre>
<p>本来ならば全ての Encoding が UTF-8 であるべきだと思います。</p>
<p><code>Init_enc_set_filesystem_encoding()</code> を以下のように修正すれば修正可能です。</p>
<pre><code>Index: localeinit.c
===================================================================
--- localeinit.c (revision 44594)
+++ localeinit.c (working copy)
@@ -53,7 +53,7 @@
int idx;
#if defined NO_LOCALE_CHARMAP
# error NO_LOCALE_CHARMAP defined
-#elif defined _WIN32 || defined __CYGWIN__
+#elif defined _WIN32 && !defined __CYGWIN__
char cp[sizeof(int) * 8 / 3 + 4];
snprintf(cp, sizeof cp, "CP%d", AreFileApisANSI() ? GetACP() : GetOEMCP());
idx = rb_enc_find_index(cp);
</code></pre> Ruby master - Feature #9347 (Open): Accept non callable argument to detecthttps://bugs.ruby-lang.org/issues/93472014-01-03T07:37:33Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently, the only argument that <code>Enumerable#detect</code> accepts is a callable object.</p>
<p>Shouldn't we accept non callable objects too?</p>
<pre><code>[42].detect(:not_found){} # => NoMethodError: undefined method `call' for :not_found:Symbol
# would return :not_found instead.
</code></pre>
<p>I'd suggest that if the given argument does not <code>respond_to? :call</code>, then it would be returned as is instead of raising an error as currently.<br>
Wouldn't this be more flexible and possibly more performant?</p>
<p>Inspired by <a href="http://stackoverflow.com/questions/20883414/why-does-enumerabledetect-need-a-proc-lambda" class="external">http://stackoverflow.com/questions/20883414/why-does-enumerabledetect-need-a-proc-lambda</a></p> Ruby master - Bug #8444 (Open): Regexp vars $~ and friends are not thread localhttps://bugs.ruby-lang.org/issues/84442013-05-24T18:15:17Zjamespharaoh (James Pharaoh)james@phsys.co.uk
<p>In the docs for the Regexp special variables, <code>$~</code> and friends, it says "These global variables are thread-local and method-local variables". However the following gives an unexpected result:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">get_proc</span>
<span class="nb">proc</span> <span class="k">do</span> <span class="o">|</span><span class="n">str</span><span class="o">|</span>
<span class="n">str</span> <span class="o">=~</span> <span class="sr">/(.+)/</span>
<span class="nb">sleep</span> <span class="mf">0.1</span>
<span class="nb">puts</span> <span class="s2">"got </span><span class="si">#{</span><span class="vg">$1</span><span class="si">}</span><span class="s2"> from </span><span class="si">#{</span><span class="n">str</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="nb">proc</span> <span class="o">=</span> <span class="n">get_proc</span>
<span class="n">t1</span> <span class="o">=</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="nb">proc</span><span class="p">.</span><span class="nf">call</span> <span class="s2">"abc"</span> <span class="p">}</span>
<span class="n">t2</span> <span class="o">=</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="nb">proc</span><span class="p">.</span><span class="nf">call</span> <span class="s2">"def"</span> <span class="p">}</span>
<span class="n">t1</span><span class="p">.</span><span class="nf">join</span>
<span class="n">t2</span><span class="p">.</span><span class="nf">join</span>
</code></pre>
<p>This outputs the following:</p>
<pre><code>got abc from abc
got abc from def
</code></pre>
<p>The expected result is of course:</p>
<pre><code>got abc from abc
got def from def
</code></pre>
<p>Clearly the variables are being scoped to the <code>get_proc</code> method and are being shared by both threads. This runs contrary to the documentation and also to expectations.</p>
<p>This behaviour should either be changed, or the documentation updated to reflect the actual behaviour.</p>
<p>Interestingly, the following does work as expected:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">proc</span> <span class="o">=</span> <span class="nb">proc</span> <span class="k">do</span> <span class="o">|</span><span class="n">str</span><span class="o">|</span>
<span class="n">str</span> <span class="o">=~</span> <span class="sr">/(.+)/</span>
<span class="nb">sleep</span> <span class="mf">0.1</span>
<span class="nb">puts</span> <span class="s2">"got </span><span class="si">#{</span><span class="vg">$1</span><span class="si">}</span><span class="s2"> from </span><span class="si">#{</span><span class="n">str</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</span>
<span class="k">end</span>
<span class="n">t1</span> <span class="o">=</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="nb">proc</span><span class="p">.</span><span class="nf">call</span> <span class="s2">"abc"</span> <span class="p">}</span>
<span class="n">t2</span> <span class="o">=</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="nb">proc</span><span class="p">.</span><span class="nf">call</span> <span class="s2">"def"</span> <span class="p">}</span>
<span class="n">t1</span><span class="p">.</span><span class="nf">join</span>
<span class="n">t2</span><span class="p">.</span><span class="nf">join</span>
</code></pre> Ruby master - Bug #7742 (Open): System encoding (Windows-1258) is not recognized by Ruby to conv...https://bugs.ruby-lang.org/issues/77422013-01-26T15:33:40ZMars (Hong Ha Dang )dhhmars9999@gmail.com
<p>I installed Railsinstaller in win8. After intall complete the screen set to</p>
<blockquote>
<p>configuration Railsinstaller on cmd (step 2). I give user name: DHH Mars and<br>
email: <a href="mailto:dhhma...@gmail.com" class="email">dhhma...@gmail.com</a>. It ran and have following massage:</p>
<p>C:/RailsInstaller/scripts/config_check.rb:64:in 'exist?': code converter not<br>
found <a href="Encoding::ConverterNotFoundError" class="external">Encoding::ConverterNotFoundError</a> from<br>
C:/RailsInstaller/scripts/config_check.rb:64:in 'main'</p>
<p>C:\Sites></p>
</blockquote>