Extending JRuby

  • 1,768 views
Uploaded on

My talk given on Oct 2 2010 at JRubyConf.

My talk given on Oct 2 2010 at JRubyConf.

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,768
On Slideshare
0
From Embeds
0
Number of Embeds
2

Actions

Shares
Downloads
11
Comments
0
Likes
3

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide
  • Ruby going on 10 years now
    Java stopped being my main programming language ~6-7 years ago. My latest Java in a Nutshell book, is brown and has a referee on the front. Java had a dot in its version at the time.




  • have a program

    Need to access some functionality in a third party library, it is either to time consuming to write yourself, or its proprietary, or boring, or so solid no bugs in years.

    The extensions is what sits between the ruby runtime and exposes the funcationality of the Awesome Library to the ruby runtime so that your ruby program can use it.


  • have a program

    Need to access some functionality in a third party library, it is either to time consuming to write yourself, or its proprietary, or boring, or so solid no bugs in years.

    The extensions is what sits between the ruby runtime and exposes the funcationality of the Awesome Library to the ruby runtime so that your ruby program can use it.


  • have a program

    Need to access some functionality in a third party library, it is either to time consuming to write yourself, or its proprietary, or boring, or so solid no bugs in years.

    The extensions is what sits between the ruby runtime and exposes the funcationality of the Awesome Library to the ruby runtime so that your ruby program can use it.


  • have a program

    Need to access some functionality in a third party library, it is either to time consuming to write yourself, or its proprietary, or boring, or so solid no bugs in years.

    The extensions is what sits between the ruby runtime and exposes the funcationality of the Awesome Library to the ruby runtime so that your ruby program can use it.


  • Hi resolution timer library for recording performance metrics at the nanosecond resolution.

    To get nanosecond resolution, you need a very specific system call on ever operating system.










  • Why would you want to take the time to create Java Extensions for use in Jruby?

    You can already easily utilize all the available Java libraries directly.
    You can make it more ruby-esque by writing a pure ruby wrapper around a Java API, as Thomas has pointed out.

    All in all, I would have to say, you would need a pretty compelling reason to do so.

  • Hi resolution timer library for recording performance metrics at the nanosecond resolution.

    To get nanosecond resolution, you need a very specific system call on ever operating system.





  • The initial require is the same
    but in JRuby, the hook leads us down a different path.
    JRuby looks for a .jar that is in the load path, and has the same path as the require
    Inside that .jar, the last item element of the require is converted from snake_case to ClassCase, and Service is tacked onto the end.

    That class is instantiated and the basicLoad method is called. This is your hook into the runtime.

    See the javadoc for LoadService.java
  • The initial require is the same
    but in JRuby, the hook leads us down a different path.
    JRuby looks for a .jar that is in the load path, and has the same path as the require
    Inside that .jar, the last item element of the require is converted from snake_case to ClassCase, and Service is tacked onto the end.

    That class is instantiated and the basicLoad method is called. This is your hook into the runtime.

    See the javadoc for LoadService.java
  • The initial require is the same
    but in JRuby, the hook leads us down a different path.
    JRuby looks for a .jar that is in the load path, and has the same path as the require
    Inside that .jar, the last item element of the require is converted from snake_case to ClassCase, and Service is tacked onto the end.

    That class is instantiated and the basicLoad method is called. This is your hook into the runtime.

    See the javadoc for LoadService.java
  • The initial require is the same
    but in JRuby, the hook leads us down a different path.
    JRuby looks for a .jar that is in the load path, and has the same path as the require
    Inside that .jar, the last item element of the require is converted from snake_case to ClassCase, and Service is tacked onto the end.

    That class is instantiated and the basicLoad method is called. This is your hook into the runtime.

    See the javadoc for LoadService.java



  • 1) Loading
    2) Initialization
    3) Class Hierarchy definition + Allocators
    4) Method definition(s)
  • Tim Felgentreff

Transcript

  • 1. Extending JRuby JRubyConf 2010 Jeremy Hinegardner
  • 2. All Work Collective Intellect
  • 3. All Play github.com/copiousfreetime
  • 4. Dull Boy @copiousfreetime
  • 5. Extensions
  • 6. Ruby Program
  • 7. Ruby Program Some Awesome Library sal.{dll,so,jar}
  • 8. Ruby Program Ruby Runtime Some Awesome Library sal.{dll,so,jar}
  • 9. Ruby Program Ruby Runtime Extension API Some Awesome Library sal.{dll,so,jar}
  • 10. Ruby Program Ruby Runtime Extension Extension API Some Awesome Library sal.{dll,so,jar}
  • 11. Hitimes
  • 12. MRI - C Extensions
  • 13. How Many of You Have ... ... A C Extension
  • 14. How Many of You Have ... USED ... A C Extension
  • 15. How Many of You Have ... USED LOOKED AT THE SOURCE CODE OF ... A C Extension
  • 16. How Many of You Have ... USED LOOKED AT THE SOURCE CODE OF WRITTEN ... A C Extension
  • 17. C Extension Trace
  • 18. C Extension Trace % irb >> require 'rubygems' >> require 'hitimes'
  • 19. C Extension Trace % irb >> require 'rubygems'| grep require % cat lib/hitimes.rb require 'hitimes/paths' >> require 'hitimes' require 'hitimes/version' require "hitimes/#{RUBY_VERSION.sub(/.d$/,'')}/hitimes_ext" ...
  • 20. C Extension Trace % irb >> require 'rubygems'| grep require % cat lib/hitimes.rb require 'hitimes/paths' >> require 'hitimes' require 'hitimes/version' require "hitimes/#{RUBY_VERSION.sub(/.d$/,'')}/hitimes_ext" % find ./lib -type f -name 'hitimes_ext*' ... ./lib/hitimes/1.8/hitimes_ext.bundle ...
  • 21. C Extension Trace % irb >> require 'rubygems'| grep require % cat lib/hitimes.rb require 'hitimes/paths' >> require 'hitimes' require 'hitimes/version' require "hitimes/#{RUBY_VERSION.sub(/.d$/,'')}/hitimes_ext" % find ./lib -type f -name 'hitimes_ext*' ... ./lib/hitimes/1.8/hitimes_ext.bundle ... % cat ext/hitimes/hitimes_ext.c void Init_hitimes_ext( ) { mH = rb_define_module("Hitimes"); eH_Error = rb_define_class_under(mH, "Error", rb_eStandardError); Init_hitimes_interval(); Init_hitimes_stats( ); }
  • 22. void Init_hitimes_interval() { mH = rb_define_module("Hitimes"); cH_Interval = rb_define_class_under( mH, "Interval", rb_cObject ); rb_define_alloc_func( cH_Interval, hitimes_interval_alloc ); rb_define_module_function( cH_Interval, "now", hitimes_interval_now, 0 ); rb_define_module_function( cH_Interval, "measure", hitimes_interval_measure, 0 ); rb_define_method( cH_Interval, "duration", hitimes_interval_duration, 0 ); rb_define_method( cH_Interval, "duration_so_far", hitimes_interval_duration_so_far, 0); rb_define_method( cH_Interval, "started?", hitimes_interval_started, 0 ); rb_define_method( cH_Interval, "running?", hitimes_interval_running, 0 ); rb_define_method( cH_Interval, "stopped?", hitimes_interval_stopped, 0 ); rb_define_method( cH_Interval, "start_instant", hitimes_interval_start_instant, 0 ); rb_define_method( cH_Interval, "stop_instant", hitimes_interval_stop_instant, 0 ); rb_define_method( cH_Interval, "start", hitimes_interval_start, 0); rb_define_method( cH_Interval, "stop", hitimes_interval_stop, 0); rb_define_method( cH_Interval, "split", hitimes_interval_split, 0); }
  • 23. JRuby - Java Extensions
  • 24. _WHY?
  • 25. _Why Not?
  • 26. Hitimes
  • 27. hitimes_instant_t hitimes_get_current_instant() { LARGE_INTEGER tick; QueryPerformanceCounter(&tick); return (hitimes_instant_t)tick.QuadPart; }
  • 28. hitimes_instant_t hitimes_get_current_instant() { LARGE_INTEGER tick; QueryPerformanceCounter(&tick); return (hitimes_instant_t)tick.QuadPart; } hitimes_instant_t hitimes_get_current_instant( ) { Nanoseconds nano = AbsoluteToNanoseconds( UpTime() ); return *( hitimes_instant_t *)&nano; }
  • 29. hitimes_instant_t hitimes_get_current_instant() { LARGE_INTEGER tick; QueryPerformanceCounter(&tick); return (hitimes_instant_t)tick.QuadPart; } hitimes_instant_t hitimes_get_current_instant( ) { Nanoseconds nano = AbsoluteToNanoseconds( UpTime() ); return *( hitimes_instant_t *)&nano; } hitimes_instant_t hitimes_get_current_instant( ) { clock_gettime( CLOCK_MONOTONIC,&time); return ( ( NANOSECONDS_PER_SECOND * (long)time.tv_sec ) + time.tv_nsec ); }
  • 30. ?
  • 31. System.nanoTime()
  • 32. Java Extension Trace
  • 33. Java Extension Trace % irb >> require 'rubygems' >> require 'hitimes'
  • 34. Java Extension Trace % irb lib/hitimes.rb % cat >> require 'rubygems' ... >> require 'hitimes' if RUBY_PLATFORM == "java" then require 'hitimes/hitimes' else ...
  • 35. Java Extension Trace % irb lib/hitimes.rb % cat >> require 'rubygems' ... >> require 'hitimes' if RUBY_PLATFORM == "java" then require 'hitimes/hitimes' else find ./lib -type f -name '*.jar' % ... ./lib/hitimes/hitimes.jar
  • 36. Java Extension Trace % irb lib/hitimes.rb % cat >> require 'rubygems' ... >> require 'hitimes' if RUBY_PLATFORM == "java" then require 'hitimes/hitimes' else find ./lib -type f -name '*.jar' % ... ./lib/hitimes/hitimes.jar % cat ext/java/src/hitimes/HitimesService.java package hitimes; [...] import org.jruby.runtime.load.BasicLibraryService; public class HitimesService implements BasicLibraryService { public boolean basicLoad( final Ruby runtime ) throws IOException { Hitimes.createHitimes( runtime ); return true; } }
  • 37. package hitimes; @JRubyModule( name = "Hitimes" ) public class Hitimes { public static RubyModule createHitimes( Ruby runtime ) { RubyModule mHitimes = runtime.defineModule("Hitimes"); RubyClass cStandardError = runtime.getStandardError(); RubyClass cHitimesError = mHitimes.defineClassUnder("Error", cStandardError, cStandardError.getAllocator()); RubyClass cHitimesStats = mHitimes.defineClassUnder("Stats", runtime.getObject(), HitimesStats.ALLOCATOR ); cHitimesStats.defineAnnotatedMethods( HitimesStats.class ); RubyClass cHitimesInterval = mHitimes.defineClassUnder("Interval", runtime.getObject(), HitimesInterval.ALLOCATOR ); Hitimes.hitimesIntervalClass = cHitimesInterval; cHitimesInterval.defineAnnotatedMethods( HitimesInterval.class ); return mHitimes; } [...] }
  • 38. Annotations @JRubyClass( name = "Hitimes::Interval" ) public class HitimesInterval extends RubyObject { ... @JRubyMethod( name = "duration", alias = { "length", "to_f", "to_seconds" } ) public IRubyObject duration() { ... } @JRubyMethod( name = "started?" ) public IRubyObject is_started() { ... } @JRubyMethod( name = "now", module = true ) public static IRubyObject now( IRubyObject self ) { ... } }
  • 39. Annotations @JRubyClass( name = "Hitimes::Interval" ) public class HitimesInterval extends RubyObject { ... @JRubyMethod( name = "measure", module = true, frame = true ) public static IRubyObject measure( IRubyObject self, Block block ) { Ruby runtime = self.getRuntime(); if ( block.isGiven() ) { IRubyObject nil = runtime.getNil(); ThreadContext context = runtime.getCurrentContext(); [...] interval.start(); block.yield( context, nil ); interval.stop(); return interval.duration(); } else { throw Hitimes.newHitimesError( runtime, "No block given to Interval.measure" ); } } }
  • 40. MRI - C Extension JRuby - Java Extension require ‘hitimes/hitimes_ext require ‘hitimes/hitimes’ lib/hitimes/hitimes_ext.so lib/hitimes/hitimes.jar public class HitimesService implements BasicLibraryService { void Init_hitimes_ext() public boolean basicLoad( ... ) { ... } } mH = rb_define_module("Hitimes"); RubyModule mHitimes = runtime.defineModule("Hitimes"); cH_Interval = rb_define_class_under( mH, "Interval", RubyClass cHitimesInterval = rb_cObject ); mHitimes.defineClassUnder("Interval", rb_define_alloc_func( cH_Interval, hitimes_interval_alloc ); runtime.getObject(), HitimesInterval.ALLOCATOR ); rb_define_module_function( cH_Interval, "measure", cHitimesInterval.defineAnnotatedMethods( HitimesInterval.class ); rb_define_method( cH_Interval,"duration", ... ) rb_define_method( cH_Interval,"started?", ... ) // Combined with the @JRubyMethod( name = ... ) rb_define_method( cH_Interval,"duration", ... ) // Annotations ...
  • 41. JRuby - C Extensions
  • 42. Jeremy Hinegardner @copiousfreetime jeremy@hinegardner.org Thanks! http://copiousfreetime.org http://twitter.com/jruby/team http://github.com/copiousfreetime/hitimes - Hitimes library http://www.serabe.com/ - several blog posts jruby extensions http://ola-bini.blogspot.com/2006/10/jruby-tutorial-4-writing-java.html http://github.com/jruby/jruby/blob/master/src/org/jruby/runtime/load/ LoadService.java http://tatice.deviantart.com/ - Operating System Icons