Project

General

Profile

Feature #20182

Updated by k0kubun (Takashi Kokubun) 4 months ago

## Proposal 

 Rewrite Array#each in Ruby https://github.com/ruby/ruby/pull/6687. 

 ```rb 
 class Array 
   def each 
     unless block_given? 
       return to_enum(:each) { self.length } 
     end 
     i = 0 
     while i < self.length 
       yield self[i] 
       i = i.succ 
     end 
     self 
   end 
 end 
 ``` 

 ## Purpose 

 Make it possible for YJIT to optimize ISEQs across `Array#each`. 

 ## Background 

 Whether JIT-compiled or not, calling Ruby from C is more expensive than calling Ruby from Ruby. It also prevents YJIT from making cross-ISEQ optimizations. 

 This is problematic especially for loop methods written in C like `Array#each` since the overhead is repeated at every iteration. 

 ## Discussions 

 There are a couple of things I'd like to discuss in this ticket: 

 1. @Eregon has pointed out that there's a race condition in the above implementation. `self[i]` would yield `nil` if the element was removed by another thread or TracePoint after `i < self.length`. Is it `Array#each`'s responsibility to atomically operate on elements, or are users supposed to avoid mutating the array in the middle of its loop? 
 2. If `Integer#<`, `Array#length`, `Integer#length`, `Integer#succ`, or `Array#[]` is overridden in an incompatible way, the Ruby implementation may not work correctly. May I assume it's acceptable?

Back