jira.codehaus.org

  • Log In Access more options
    • Online Help
    • Keyboard Shortcuts
    • About JIRA
    • JIRA Credits
    • What?s New
  • Dashboards Access more options (Alt+d)
  • Projects Access more options (Alt+p)
  • Issues Access more options (Alt+i)
  • JRuby
  • JRUBY-2621

Long bodies of code that don't appear at root don't split and can blow the 64k bytecode cap

  • Log In
  • Views
    • XML
    • Word
    • Printable

Details

  • Type: Bug Bug
  • Status: Resolved Resolved
  • Priority: Major Major
  • Resolution: Fixed
  • Affects Version/s: None
  • Fix Version/s: JRuby 1.6
  • Component/s: Compiler
  • Labels:
    None

Description

This will obviously affect performance of ruby_parser quite a bit:

~/NetBeansProjects/jruby ➔ jruby -J-Djruby.jit.logging.verbose=true -X+C --server -rubygems -rbenchmark -e "gem :ruby_parser; require 'ruby_parser'; 5.times {puts Benchmark.measure {RubyParser.new.parse(File.read('lib/ruby/1.8/rdoc/parsers/parse_rb.rb'))}}"
could not compile: /Users/headius/NetBeansProjects/jruby/lib/ruby/gems/1.8/gems/ruby_parser-1.0.0/lib/ruby_parser.rb because of: "Invalid method Code length 82165 in class file ruby/Users/headius/NetBeansProjects/jruby/lib/ruby/gems/$1_dot_8/gems/ruby_parser_minus_1_dot_0_dot_0/lib/ruby_parser"
java.lang.ClassFormatError: Invalid method Code length 82165 in class file ruby/Users/headius/NetBeansProjects/jruby/lib/ruby/gems/$1_dot_8/gems/ruby_parser_minus_1_dot_0_dot_0/lib/ruby_parser
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:675)
	at org.jruby.util.JRubyClassLoader.defineClass(JRubyClassLoader.java:21)
	at org.jruby.compiler.impl.StandardASMCompiler.loadClass(StandardASMCompiler.java:159)
	at org.jruby.Ruby.tryCompile(Ruby.java:464)
	at org.jruby.Ruby.compileAndLoadFile(Ruby.java:2041)
	at org.jruby.runtime.load.ExternalScript.load(ExternalScript.java:56)
	at org.jruby.runtime.load.LoadService.smartLoad(LoadService.java:320)
	at org.jruby.runtime.load.LoadService.require(LoadService.java:346)
	at org.jruby.RubyKernel.require(RubyKernel.java:769)
  • Options
    • Sort By Name
    • Sort By Date
    • Ascending
    • Descending
    • Download All

Attachments

  1. Text File
    code_length_error.txt
    10/Feb/10 9:51 AM
    9 kB
    albert ramstedt

Issue Links

is depended upon by

Bug - A problem which impairs or prevents the functions of the product. JRUBY-4757 addressable gem doesn't work with --fast

  • Major - Major loss of function.
  • Closed - The issue is considered finished, the resolution is correct. Issues which are not closed can be reopened.

Activity

Ascending order - Click to sort in descending order
  • All
  • Comments
  • Work Log
  • History
  • Activity
Hide
Permalink
Charles Oliver Nutter added a comment - 04/Jul/08 8:27 AM

I discovered what the problem was with ruby_parser...it's the main script. It initializes a number of seriously gigantic arrays for the Ruby parser productions. I think there are several of these arrays that would fail to compile individually, much less all of them as the body of a method. And because they're gigantic, they can't easily be split into multiple methods.

This should generally affect only +C compilation since it's in the root of the script. But it's something to look out for in the future. I'll leave this open to try to explore any way possible to compile this script. Toughy though.

Show
Charles Oliver Nutter added a comment - 04/Jul/08 8:27 AM I discovered what the problem was with ruby_parser...it's the main script. It initializes a number of seriously gigantic arrays for the Ruby parser productions. I think there are several of these arrays that would fail to compile individually, much less all of them as the body of a method. And because they're gigantic, they can't easily be split into multiple methods. This should generally affect only +C compilation since it's in the root of the script. But it's something to look out for in the future. I'll leave this open to try to explore any way possible to compile this script. Toughy though.
Hide
Permalink
Charles Oliver Nutter added a comment - 04/Jul/08 11:18 AM

Some experimentation helped me find out that the upper bound of a literal int array is somewhere around 4700 elements. Then it crosses the 65k limit for an individual method.

The giant arrays in question are generated by RACC, so there's little change to get them changed. Instead we should explore the possibility of having arrays over a particular size force splitting by compiling as their own array-populating methods. I'm not going to do this right now, but it's something we'll want to look into in the future for cases like the Ruby parser.

Show
Charles Oliver Nutter added a comment - 04/Jul/08 11:18 AM Some experimentation helped me find out that the upper bound of a literal int array is somewhere around 4700 elements. Then it crosses the 65k limit for an individual method. The giant arrays in question are generated by RACC, so there's little change to get them changed. Instead we should explore the possibility of having arrays over a particular size force splitting by compiling as their own array-populating methods. I'm not going to do this right now, but it's something we'll want to look into in the future for cases like the Ruby parser.
Hide
Permalink
Charles Oliver Nutter added a comment - 16/Jul/08 3:00 AM

This is a nontrivial bit of compiler twiddling for very little gain, so I'm punting it to post 1.1.3.

Show
Charles Oliver Nutter added a comment - 16/Jul/08 3:00 AM This is a nontrivial bit of compiler twiddling for very little gain, so I'm punting it to post 1.1.3.
Hide
Permalink
Charles Oliver Nutter added a comment - 14/Apr/09 12:17 AM

I think we should make an attempt at this for 1.3, since it turns out merb can generate large enough routing tables to blow this limit, and that model of routing is coming to Rails 3.

Show
Charles Oliver Nutter added a comment - 14/Apr/09 12:17 AM I think we should make an attempt at this for 1.3, since it turns out merb can generate large enough routing tables to blow this limit, and that model of routing is coming to Rails 3.
Hide
Permalink
Charles Oliver Nutter added a comment - 11/May/09 6:36 PM

This may require the upcoming work on a new compiler infrastructure, since it's currently not easy to split anything that isn't at root. A better compiler could possibly pull out subsections of code without damaging the flow of the program.

Show
Charles Oliver Nutter added a comment - 11/May/09 6:36 PM This may require the upcoming work on a new compiler infrastructure, since it's currently not easy to split anything that isn't at root. A better compiler could possibly pull out subsections of code without damaging the flow of the program.
Hide
Permalink
Charles Oliver Nutter added a comment - 05/Oct/09 2:26 PM

There is additional work needed to split methods more intelligently, but at least for JIT mode we did institute a bytecode size cap. This should help prevent methods from jitting if they would end up too big, and we can look at getting splitting in place with the newer compiler stuff. 1.x+

Show
Charles Oliver Nutter added a comment - 05/Oct/09 2:26 PM There is additional work needed to split methods more intelligently, but at least for JIT mode we did institute a bytecode size cap. This should help prevent methods from jitting if they would end up too big, and we can look at getting splitting in place with the newer compiler stuff. 1.x+
Hide
Permalink
albert ramstedt added a comment - 10/Feb/10 9:50 AM

+1 for this problem.

I had this problem in production, in an app with a relatively large route setup.

Rails 2.1.2, jruby 1.3.1

Attached the gf log traceback.

Show
albert ramstedt added a comment - 10/Feb/10 9:50 AM +1 for this problem. I had this problem in production, in an app with a relatively large route setup. Rails 2.1.2, jruby 1.3.1 Attached the gf log traceback.
Hide
Permalink
albert ramstedt added a comment - 10/Feb/10 9:51 AM

Gf log of the error

Show
albert ramstedt added a comment - 10/Feb/10 9:51 AM Gf log of the error
Hide
Permalink
Charles Oliver Nutter added a comment - 10/Feb/10 10:41 AM

A little exploration shows that 2.1.2 generates a single extremely large method with a lot of branches and a lot of useless code. Rails 2.3 appears to generate a tree of methods, or graph-walking code. So the giant routing method appears to be mostly a 2.1.2 artifact.

As for the error, I suspect it does not affect production; if you're running on a reasonably recent JRuby, all errors from jitting should be caught and as a result the method just stays interpreted. Interpreted mode for this giant method isn't great but it won't affect the behavior of the application. It's possible that some logging somewhere has caused this error to be displayed for you.

I'll look into JRuby 1.3.1 code to see if perhaps we were logging unnecessarily, or else not capturing the error.

Show
Charles Oliver Nutter added a comment - 10/Feb/10 10:41 AM A little exploration shows that 2.1.2 generates a single extremely large method with a lot of branches and a lot of useless code. Rails 2.3 appears to generate a tree of methods, or graph-walking code. So the giant routing method appears to be mostly a 2.1.2 artifact. As for the error, I suspect it does not affect production; if you're running on a reasonably recent JRuby, all errors from jitting should be caught and as a result the method just stays interpreted. Interpreted mode for this giant method isn't great but it won't affect the behavior of the application. It's possible that some logging somewhere has caused this error to be displayed for you. I'll look into JRuby 1.3.1 code to see if perhaps we were logging unnecessarily, or else not capturing the error.
Hide
Permalink
Charles Oliver Nutter added a comment - 10/Feb/10 11:30 AM

I found that in JRuby 1.3.1, the JITCompiler's exception handling was unconditionally logging errors, which means this tends to make more noise than necessary on a typical server. The logging should only fire once per failed JIT method, and there should be no negative impact to execution.

So this remains an open bug, of course, but for noisy error cases like Albert's, the recommendation is to upgrade JRuby or ignore the error logging (1.4.0 does not appear to have this rogue logging).

Show
Charles Oliver Nutter added a comment - 10/Feb/10 11:30 AM I found that in JRuby 1.3.1, the JITCompiler's exception handling was unconditionally logging errors, which means this tends to make more noise than necessary on a typical server. The logging should only fire once per failed JIT method, and there should be no negative impact to execution. So this remains an open bug, of course, but for noisy error cases like Albert's, the recommendation is to upgrade JRuby or ignore the error logging (1.4.0 does not appear to have this rogue logging).
Hide
Permalink
Charles Oliver Nutter added a comment - 27/Apr/10 12:03 PM

A partial fix for this was pushed to jruby-1_5 in 829cd0a and to master in 6ca0f75. That fix allows hashes and arrays containing all literals (or containing other hashes and arrays that are all literals) to "chunk" into several methods. This avoids blowing the method size cap for most cases (ruby_parser and addressable being the two I know of, the latter from JRUBY-4757) and may fix other cases of really big hashes and arrays.

There's no general fix for this yet, and large bodies of non-literals can still get too large.

Show
Charles Oliver Nutter added a comment - 27/Apr/10 12:03 PM A partial fix for this was pushed to jruby-1_5 in 829cd0a and to master in 6ca0f75. That fix allows hashes and arrays containing all literals (or containing other hashes and arrays that are all literals) to "chunk" into several methods. This avoids blowing the method size cap for most cases (ruby_parser and addressable being the two I know of, the latter from JRUBY-4757) and may fix other cases of really big hashes and arrays. There's no general fix for this yet, and large bodies of non-literals can still get too large.
Hide
Permalink
Hiro Asari added a comment - 17/May/12 9:43 PM

Current status:

jruby -v -J-Djruby.jit.logging.verbose=true -X+C --server -rubygems -rbenchmark -e "gem 'ruby_parser'; require 'ruby_parser'; 5.times {puts Benchmark.measure {RubyParser.new.parse(File.read('lib/ruby/1.8/rdoc/parsers/parse_rb.rb'))}}"
jruby 1.7.0.preview1 (ruby-1.9.3-p203) (2012-05-17 4f0b781) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_04) [darwin-x86_64-java]
  5.490000   0.130000   5.620000 (  3.848000)
  2.650000   0.100000   2.750000 (  1.848000)
  1.460000   0.010000   1.470000 (  1.075000)
  1.070000   0.010000   1.080000 (  0.877000)
  1.190000   0.040000   1.230000 (  1.093000)
Show
Hiro Asari added a comment - 17/May/12 9:43 PM Current status:
jruby -v -J-Djruby.jit.logging.verbose=true -X+C --server -rubygems -rbenchmark -e "gem 'ruby_parser'; require 'ruby_parser'; 5.times {puts Benchmark.measure {RubyParser.new.parse(File.read('lib/ruby/1.8/rdoc/parsers/parse_rb.rb'))}}"
jruby 1.7.0.preview1 (ruby-1.9.3-p203) (2012-05-17 4f0b781) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_04) [darwin-x86_64-java]
  5.490000   0.130000   5.620000 (  3.848000)
  2.650000   0.100000   2.750000 (  1.848000)
  1.460000   0.010000   1.470000 (  1.075000)
  1.070000   0.010000   1.080000 (  0.877000)
  1.190000   0.040000   1.230000 (  1.093000)
Hide
Permalink
Charles Oliver Nutter added a comment - 18/May/12 1:20 PM

I'm going to mark this fixed, and we'll deal with specific failure cases and files as they come up. No open-ended bugs!

Show
Charles Oliver Nutter added a comment - 18/May/12 1:20 PM I'm going to mark this fixed, and we'll deal with specific failure cases and files as they come up. No open-ended bugs!

People

  • Assignee:
    Charles Oliver Nutter
    Reporter:
    Charles Oliver Nutter
Vote (1)
Watch (1)

Dates

  • Created:
    08/Jun/08 12:21 PM
    Updated:
    Friday 1:20 PM
    Resolved:
    Friday 1:20 PM
  • Atlassian JIRA (v5.0.4#731-sha1:3aa7374)
  • Report a problem
  • Powered by a free Atlassian JIRA open source license for Codehaus. Try JIRA - bug tracking software for your team.