• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content

Loading…

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

Like this presentation? Why not share!

Learn about JRuby Internals from one of the JRuby Lead Developers, Thomas Enebo

on

  • 2,076 views

At an event hosted at LinkedIn on November 2, 2010, "JRuby Guy", Thomas Enebo gave us an introduction to JRuby internals, and what about the intenals a new contributor might need to know to get ...

At an event hosted at LinkedIn on November 2, 2010, "JRuby Guy", Thomas Enebo gave us an introduction to JRuby internals, and what about the intenals a new contributor might need to know to get started in contributing to the JRuby project.

** check out the slides from this presentation at: http://marakana.com/f/197 **

Statistics

Views

Total Views
2,076
Views on SlideShare
2,066
Embed Views
10

Actions

Likes
4
Downloads
31
Comments
0

4 Embeds 10

http://us-w1.rockmelt.com 4
http://twitter.com 3
https://twitter.com 2
http://static.slidesharecdn.com 1

Accessibility

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />

Learn about JRuby Internals from one of the JRuby Lead Developers, Thomas Enebo Learn about JRuby Internals from one of the JRuby Lead Developers, Thomas Enebo Presentation Transcript

  • JRuby Internals Thomas E. Enebo Engine Yard, Inc. + www.jruby.org
  • Who am I? • JRuby Guy • 4+ years as “day job” + few years as hobby • Almost 10 years of Ruby • 15+ years of Java • Friendly • Likes Beer
  • Goals • “JRuby Internals Talk”
  • The Coolest Internals Preso http://prezi.com/tsuouxb3z4ln/jruby-hacking-guide/
  • What did he say?!?!???
  • What to Cover? • Our codebase is large • 241,000 lines of Java • 170,000 lines of Ruby (ignoring 1.9 stdlib) • 30 minutes is not long enough
  • What internals knowledge would help a new contributor?
  • Getting + Building git clone git://github.com/jruby/jruby.git Install Java JDK + Apache Ant enebo:15:07 ~/work/jruby 1058% ant Buildfile: /Users/enebo/work/jruby/ build.xml init:
  • What to work on? • Scratch your own itch • Browse issues on Jira: • http://jira.codehaus.org/browse/JRUBY • No FEAR!!! • Java is easy. • Internals not too tough?
  • org.jruby.Ruby*.java
  • org.jruby.Ruby • Main context for an individual runtime • hard reference to class hierachy • Stores all important stuff • in,out,error,finalizers • API for retreiving or creating objects • RubyFixnum newFixnum(long value);
  • Bootstrapping • newInstance() ->init() ->bootstrap() ->initCore() public final class Ruby { private void initCore() { // ... other classes elided ... if (profile.allowClass("Array")) { RubyArray.createArrayClass(this); } } }
  • RubyArray Bootstrapping public static RubyClass createArrayClass(Ruby r) { // ... stuff elided ... arrayc = r.defineClass("Array", r.getObject(), ARRAY_ALLOCATOR); arrayc.includeModule(r.getEnumerable()); } • Ruby relationships defined by methods • ....not by Java inheritance relationships
  • RubyArray Bootstrapping Array Enumerable Object org.jruby.RubyClass superClass org.jruby.RubyModule superClass org.jruby.RubyClass Java field Actually an IncludedModuleWrapper (beyond scope of tonight)
  • RubyArray Bootstrapping public class RubyArray extends RubyObject implements List { public static RubyClass createArrayClass(Ruby r) { //... elided arrayc.defineAnnotatedMethods(RubyArray.class); } @JRubyMethod(name = "length", alias = "size") public IRubyObject length() { return getRuntime().newFixnum(realLength); } } • Annotations FTW
  • @JRubyMethod @JRubyMethod public IRubyObject insert() {} @JRubyMethod(name = "insert", compat = RUBY1_8) public IRubyObject insert(IRubyObject arg) { ... } @JRubyMethod(name = "insert", compat = RUBY1_8) public IRubyObject insert(IRubyObject arg1, IRubyObject arg2) { ... } @JRubyMethod(name = "insert", required=1, rest=true, compat=RUBY1_8) public IRubyObject insert(IRubyObject[] args) { ... }
  • @JRubyMethod • Java args are part of annotation @JRubyMethod(name = "each", frame = true) public IRubyObject each(Block block) { if (block.isGiven()) { return eachCommon(block); } else { return enumeratorize(getRuntime(), this, "each"); } }
  • Java Live Object Graph Array org.jruby.RubyClass org.jruby.RubyModule org.jruby.RubyObject extends extends class class class extends org.jruby.RubyBasicObject class implements org.jruby.IRubyObject interface
  • Java Live Object Graph Array org.jruby.RubyClass org.jruby.RubyModule org.jruby.RubyObject extends extends class class class extends org.jruby.RubyBasicObject IRubyObject callMethod(String name, ...) {} class implements org.jruby.IRubyObject IRubyObject callMethod(String name, ...); interface
  • Java Live Object Graph Array org.jruby.RubyClass org.jruby.RubyModule org.jruby.RubyObject extends extends class class class DynamicMethod searchMethod(String name) extends Map<String, DynamicMethod> methods org.jruby.RubyBasicObject class implements org.jruby.IRubyObject interface
  • Java Live Object Graph Array org.jruby.RubyClass org.jruby.RubyModule org.jruby.RubyObject extends extends class class class extends “class” “new” [1,2,3,4] extends org.jruby.RubyBasicObject org.jruby.RubyArray class callMethod(String name, ...) {} implements IRubyObject[] values; IRubyObject eltInternal(int offset) {...} org.jruby.IRubyObject interface
  • Argument Handling @JRubyMethod(name = "insert", compat = RUBY1_8) public IRubyObject insert(IRubyObject arg) { ... } • IRubyObject is everywhere • Many methods return value type or nil • We never know what someone will pass • ...and sometimes that is ok
  • Argument handling is a hot mess! • Sometimes it is MRI’s fault • No coercion • Inconsistent (to_i, to_int, oh my) • Can be ours • Uncommented optimization • Compatibility can be rough!
  • Argument Handling @JRubyMethod(name = {"[]", "slice"}, compat = RUBY1_8) public IRubyObject aref(IRubyObject arg0) { assert !arg0.getRuntime().is1_9(); weird regression if (arg0 instanceof RubyFixnum) optimization return entry(((RubyFixnum)arg0).getLongValue()); if (arg0 instanceof RubySymbol) wacky MRI error throw getRuntime().newTypeError("Symbol as array index"); return arefCommon(arg0); }
  • Argument Handling private IRubyObject arefCommon(IRubyObject arg0) { if (arg0 instanceof RubyRange) { uncommon type long[] beglen = ((RubyRange) arg0).begLen(realLength, 0); return beglen == null ? getRuntime().getNil() : subseq(beglen[0], beglen[1]); } return entry(RubyNumeric.num2long(arg0)); weirder type }
  • Argument Handling From this point on is heavily tested for MRI compatibility and tuned public static long num2long(IRubyObject arg) { if (arg instanceof RubyFixnum) { already handled return ((RubyFixnum) arg).getLongValue(); } else { return other2long(arg); } }
  • Argument Handling long other2long(IRubyObject arg) throws RaiseException { if (arg.isNil()) { special case throw arg.getRuntime().newTypeError("no implicit conversion from nil to integer"); } else if (arg instanceof RubyFloat) { return float2long((RubyFloat)arg); } else if (arg instanceof RubyBignum) { return RubyBignum.big2long((RubyBignum) arg); } return arg.convertToInteger().getLongValue(); coercion!!!! }
  • Argument Handling public RubyInteger convertToInteger() { return convertToInteger("to_int"); } public static final IRubyObject convertToType(IRubyObject obj, RubyClass target, String convertMethod, boolean raise) { if (!obj.respondsTo(convertMethod)) { method lookup! return handleUncoercibleObject(raise, obj, target); } return obj.callMethod(obj.getRuntime().getCurrentContext(), convertMethod); method lookup + } call An aside: Optimization on an uncommon case?
  • The End...? • Simple layout of static and live objects • Ruby vs Java inheritance relationships • Simple understanding of method bindings • Brief glimpse at argument coercion • Simple?
  • 10k view of runtime
  • Parsing • org.jruby.lexer.* (handwritten MRI port) def foo() Creates sequence of tokens kDEF, tIdentifier(‘foo’), tLPAREN, tRPAREN
  • Parsing • org.jruby.parser.*.y • Jay compiler-compiler • Makes an AST representation of source $1 $2 $3 $4 $5 $6 | kIF expr_value then compstmt if_tail kEND { $$ = new IfNode($1.getPosition(), support.getConditionNode($2), $4, $5); }
  • Abstract Syntax Tree jruby -S ast simple.rb AST: def hello(a) RootNode 0 puts "Hello #{a}" NewlineNode 0 end DefnNode:hello 0 ArgumentNode:hello 0 ArgsPreOneArgNode 0 ListNode 0 ArgumentNode:a 0 NewlineNode 1 FCallOneArgNode:puts 1 ArrayNode 1 DStrNode 1 StrNode 1 EvStrNode 1 NewlineNode 1 LocalVarNode:a 1
  • Current Interpreter • Every Node has an interpret() method • Call on RootNode and watch it go! public final class CallOneArgNode extends CallNode { public IRubyObject interpret(Ruby r, ThreadContext c, IRubyObject self, Block aBlock) { return callAdapter.call(c, self, getReceiverNode().interpret(r, c, self, aBlock), arg1.interpret(r, c, self, aBlock)); } }
  • Methods • Mixed Mode org.jruby.internal.runtime.methods.* DefaultMethod switches to this if active first called enough InterpretedMethod JittedMethod ...and can compile
  • DefnNode:hello 0 ArgumentNode:hello 0 Compiler ArgsPreOneArgNode 0 ListNode 0 ArgumentNode:a 0 NewlineNode 1 FCallOneArgNode:puts 1 ArrayNode 1 DStrNode 1 StrNode 1 EvStrNode 1 NewlineNode 1 LocalVarNode:a 1 • Walk AST and generate bytecode for a class • Monomorphic path • It is bytecode and not IfNode.interpret • Optimizations based on analyzing tree of nodes
  • http://www.pragprog.com/titles/jruby/using-jruby
  • Thanks • twitter: @tom_enebo • http://www.github.com/jruby/jruby.git • http://www.jruby.org/ • http://prezi.com/tsuouxb3z4ln/jruby-hacking- guide/ • http://www.pragprog.com/titles/jruby/using- jruby