JRuby 9.1.*.* on multiple platforms incorrectly handles block in `[]` method calls #4217

Closed
ab opened this Issue Oct 10, 2016 · 4 comments

Projects

None yet

2 participants

@ab
ab commented Oct 10, 2016

JRuby starting with 9.1.0.0 and affecting all 9.1.x.x versions appears to incorrectly handle blocks passed as procs to the special [] method.

In MRI ruby 2.x and in jruby 9.0.5.0, foo[i, &block] works as expected.
In jruby 9.1.x.x, the block is not passed through and the method receives nil instead.

Versions tested

Tested jruby versions on OS X:

  • jruby 9.0.5.0 (2.2.3) 2016-01-26 7bee00d Java HotSpot(TM) 64-Bit Server VM 25.102-b14 on 1.8.0_102-b14 +jit [darwin-x86_64]
  • jruby 9.1.0.0 (2.3.0) 2016-05-02 a633c63 Java HotSpot(TM) 64-Bit Server VM 25.102-b14 on 1.8.0_102-b14 +jit [darwin-x86_64]
  • jruby 9.1.1.0 (2.3.0) 2016-05-19 fe84e89 Java HotSpot(TM) 64-Bit Server VM 25.102-b14 on 1.8.0_102-b14 +jit [darwin-x86_64]
  • jruby 9.1.2.0 (2.3.0) 2016-05-26 7357c8f Java HotSpot(TM) 64-Bit Server VM 25.102-b14 on 1.8.0_102-b14 +jit [darwin-x86_64]
  • jruby 9.1.3.0 (2.3.1) 2016-08-29 a2a3b29 Java HotSpot(TM) 64-Bit Server VM 25.102-b14 on 1.8.0_102-b14 +jit [darwin-x86_64]
  • jruby 9.1.4.0 (2.3.1) 2016-09-01 2e1327f Java HotSpot(TM) 64-Bit Server VM 25.102-b14 on 1.8.0_102-b14 +jit [darwin-x86_64]
  • jruby 9.1.5.0 (2.3.1) 2016-09-07 036ce39 Java HotSpot(TM) 64-Bit Server VM 25.102-b14 on 1.8.0_102-b14 +jit [darwin-x86_64]

Tested jruby versions on linux:

  • jruby 9.0.5.0 (2.2.3) 2016-01-26 7bee00d OpenJDK 64-Bit Server VM 25.91-b14 on 1.8.0_91-8u91-b14-3ubuntu1~16.04.1-b14 +jit [linux-amd64]
  • jruby 9.1.5.0 (2.3.1) 2016-09-07 036ce39 OpenJDK 64-Bit Server VM 25.91-b14 on 1.8.0_91-8u91-b14-3ubuntu1~16.04.1-b14 +jit [linux-x86_64]

What is especially interesting is that calling the :[] method with send() passes the block through correctly.

Test script

#!/usr/bin/env ruby

class Foo
  attr_reader :failed

  def initialize
    @failed = false
  end

  def [](foo, &block)
    if block_given?
      puts "block_given, block: " + block.inspect
    else
      puts "NOT block_given, block: " + block.inspect
      @failed = true
    end
  end

  def test_method(foo, &block)
    if block_given?
      puts "block_given, block: " + block.inspect
    else
      puts "NOT block_given, block: " + block.inspect
      @failed = true
    end
  end
end


f = Foo.new

puts '--'
puts RUBY_DESCRIPTION

block = proc {|r| r}

puts
puts 'Test 1: f[&block]'
f['foo', &block]

puts
puts 'Test 2: test_method(&block)'
f.test_method('foo', &block)

puts
puts 'Test 3: f.[](&block)'
f.[]('foo', &block)

puts
puts 'Test 4: f.public_send(:[], &block)'
f.public_send(:[], 'foo', &block)

if f.failed
  puts 'FAILED'
  exit 1
else
  puts 'Succeeded'
end

Results

Sample output from successful MRI ruby 2.3.1

ruby 2.2.5p319 (2016-04-26 revision 54774) [x86_64-linux]

Test 1: f[&block]
block_given, block: #<Proc:0x00556f28d89dd8@./test.rb:35>

Test 2: test_method(&block)
block_given, block: #<Proc:0x00556f28d89dd8@./test.rb:35>

Test 3: f.[](&block)
block_given, block: #<Proc:0x00556f28d89dd8@./test.rb:35>

Test 4: f.public_send(:[], &block)
block_given, block: #<Proc:0x00556f28d89dd8@./test.rb:35>
Succeeded

Sample output from successful jruby 9.0.5.0

jruby 9.0.5.0 (2.2.3) 2016-01-26 7bee00d OpenJDK 64-Bit Server VM 25.91-b14 on 1.8.0_91-8u91-b14-3ubuntu1~16.04.1-b14 +jit [linux-amd64]

Test 1: f[&block]
block_given, block: #<Proc:0x9629756@./test.rb:35>

Test 2: test_method(&block)
block_given, block: #<Proc:0x9629756@./test.rb:35>

Test 3: f.[](&block)
block_given, block: #<Proc:0x9629756@./test.rb:35>

Test 4: f.public_send(:[], &block)
block_given, block: #<Proc:0x9629756@./test.rb:35>
Succeeded

Sample output from failing jruby 9.1.5.0

jruby 9.1.5.0 (2.3.1) 2016-09-07 036ce39 OpenJDK 64-Bit Server VM 25.91-b14 on 1.8.0_91-8u91-b14-3ubuntu1~16.04.1-b14 +jit [linux-x86_64]

Test 1: f[&block]
NOT block_given, block: nil

Test 2: test_method(&block)
block_given, block: #<Proc:0x6e0e048a@./test.rb:35>

Test 3: f.[](&block)
NOT block_given, block: nil

Test 4: f.public_send(:[], &block)
block_given, block: #<Proc:0x6e0e048a@./test.rb:35>
FAILED

Versions 9.1.0.0, 9.1.1.0, 9.1.2.0, 9.1.3.0, 9.1.4.0, and 9.1.5.0 are all affected.

@headius
Member
headius commented Oct 11, 2016

Thanks for the great bug report! I would guess we're simply not passing the block through for [].

@headius
Member
headius commented Oct 11, 2016

Results the same in JIT and interpreter. Seems to only affect the cases where the block is passed along with arguments, since f[&block] and f.[&block] work correctly.

@headius
Member
headius commented Oct 11, 2016

Looks like this is an overzealous optimization in 2d9ff09...I'm not checking single-arg array dereference calls for a closure, which would disqualify them from this optimization.

@headius headius closed this in feba193 Oct 11, 2016
@headius headius added this to the JRuby 9.1.6.0 milestone Oct 11, 2016
@ab
ab commented Oct 11, 2016

👍 Thanks!

@ab ab added a commit to rest-client/rest-client that referenced this issue Oct 11, 2016
@ab ab Skip broken test on older jruby 9.1.*.* releases. 89fab49
@ab ab referenced this issue in rest-client/rest-client Oct 11, 2016
Merged

Skip broken test on older jruby 9.1.*.* releases. #533

@eregon eregon added a commit to ruby/spec that referenced this issue Oct 29, 2016
@headius @eregon headius + eregon Spec for passing a block to forms of [] method. f06c18d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment