SlideShare a Scribd company logo
Building Languages
                               for the JVM
                               Charles Oliver Nutter




Friday, November 4, 2011
Me

                    • Charles Oliver Nutter
                    • JRuby and JVM guy
                    • “headius” on most services
                    • headius@headius.com

Friday, November 4, 2011
Who Was I?

                    • Java EE architect
                     • Successfully!
                    • Never wrote a parser
                    • Never wrote a compiler
                    • But I wanted to learn how...

Friday, November 4, 2011
You

                    • Java?
                    • Ruby?
                    • Python?
                    • C#?
                    • Other?

Friday, November 4, 2011
Why Create Languages?

                    • Nothing is perfect
                    • New problems need new solutions
                    • Language design can be fun
                    • Fame and fortune?
                     • Not really.

Friday, November 4, 2011
Why Impl a Language?
                    • To learn it?
                     • Sort of...
                    • To learn the target platform
                     • Definitely!
                    • Fame and fortune?
                     • Well...getting there...
Friday, November 4, 2011
Challenges

                    • Community
                    • Platform
                    • Specifications
                    • Resources

Friday, November 4, 2011
Community

                    • Investment in status quo
                    • Afraid to stand out
                    • Known quantities
                    • Everything else sucks
                    • Gotta get paid!

Friday, November 4, 2011
Platform
                    • Matching language semantics
                     • JVM designed around Java
                     • JVM hides underlying platform
                    • Challenging to use
                     • Not bad...C/++ would be way worse
                    • Community may hate it ;-)
Friday, November 4, 2011
Specifications
                    •      Incomplete
                           •   Ruby had none for years
                           •   ...and no complete test suites
                    •      Difficult to implement
                           •   Low level features
                           •   Single-implementation quirks
                    •      Hard or impossible to optimize


Friday, November 4, 2011
Resources

                    • You gotta eat
                    • Not much money in language work
                    • Some parts are hard
                    • OSS is a necessity

Friday, November 4, 2011
Why JVM?

                    • Because I am lazy
                    • Because VMs are *hard*
                    • Because I can’t be awesome at everything


Friday, November 4, 2011
Ok, Why Really?
                    • Cross-platform
                    • Libraries
                    • Languages
                    • Memory management
                    • Tools
                    • OSS
Friday, November 4, 2011
Cross-platform

                    • OpenJDK: Linux, Windows, Solaris, OS X,
                           xBSD
                    • J9: Linux, zLinux, AS/400, ...
                    • HP: OpenVMS, HP/UX, ...
                    • Dalvik (Android): Linux on ARM, x86

Friday, November 4, 2011
Libraries

                    • For any need, a dozen libraries
                     • And a couple of them are good!
                    • Cross-platform
                    • Leading edge

Friday, November 4, 2011
Selection of languages
                    • Java
                    • Scala
                    • Clojure
                    • JRuby
                    • Mirah
                    • Jython, Groovy, Fantom, Kotlin, Ceylon, ...
Friday, November 4, 2011
Memory management

                    • Best GCs in the world
                    • Fastest object allocation
                    • Safe escape hatches like NIO


Friday, November 4, 2011
Tools

                    • Debugging
                    • Profiling
                    • Monitoring
                    • JVM internals

Friday, November 4, 2011
Open source?

                    • FOSS reference impl (OpenJDK)
                    • Mostly OSS libraries
                    • Heavy OSS culture
                    • Strong OSS influence in OpenJDK core

Friday, November 4, 2011
Case Study: JRuby



Friday, November 4, 2011
Ruby on the JVM

                    • All of Ruby’s power and beauty
                    • Solid VM underneath
                    • “Just another JVM language”


Friday, November 4, 2011
JVM Language
                    •      Full interop with Java
                           •   Tricky to do...
                           •   Very rewarding for 99% case
                    •      VM concerns solved
                           •   No need to write a GC
                           •   No need to write a JIT
                           •   ...oh, but wait...


Friday, November 4, 2011
More than a JVM
                              language
                    • Use native code where JDK fails us
                    • Paper over ugly bits like CLASSPATH
                    • Matching Ruby semantics exactly*
                    • Push JVM forward too!

Friday, November 4, 2011
Playing with JRuby

                    • Simple IRB demo
                    • JRuby on Rails - see Jano’s talk tomorrow
                    • JRuby performance
                    • PotC (???)

Friday, November 4, 2011
How did we do it?



Friday, November 4, 2011
JRuby Architecture

                    • Parser
                    • Abstract Syntax Tree (AST)
                    • Intermediate Representation (IR)
                    • Core classes
                    • Compiler

Friday, November 4, 2011
Parser

                    • Port of MRI’s Bison grammar
                    • “Jay” parser generator for Java
                    • Hand-written lexer
                    • Nearly as fast as the C version
                     • ...once it gets going

Friday, November 4, 2011
system ~/projects/jruby $ jruby -y -e "1 + 1"
   push	 state 0	 value null
   reduce	 tate 0	 uncover 0	
          s                  rule (1) $$1 :
   goto	 from state 0 to 2
   push	 state 2	 value null
   lex	 tate 2	 reading tIDENTIFIER	 value Token { Value=load,
      s
   Position=file:/Users/headius/projects/jruby/lib/jruby.jar!/
   jruby/kernel.rb:6}
   shift	from state 2 to 33
   push	 state 33	 value Token { Value=load, Position=file:/Users/
   headius/projects/jruby/lib/jruby.jar!/jruby/kernel.rb:6}
   lex	 tate 33	 reading tSTRING_BEG	 value Token { Value=',
      s
   Position=file:/Users/headius/projects/jruby/lib/jruby.jar!/
   jruby/kernel.rb:6}
   reduce	 tate 33	 uncover 2	
          s                  rule (487) operation : tIDENTIFIER
   goto	 from state 2 to 62
   push	 state 62	 value Token { Value=load, Position=file:/Users/
   headius/projects/jruby/lib/jruby.jar!/jruby/kernel.rb:6}
   reduce	 tate 62	 uncover 62	 rule (252) $$6 :
          s



Friday, November 4, 2011
system ~/projects/jruby $ jruby -y -e "1 + 1"
   push	 state 0	 value null
   reduce	 tate 0	 uncover 0	
          s                  rule (1) $$1 :
   goto	 from state 0 to 2
   push	 state 2	 value null
   lex	 tate 2	 reading tIDENTIFIER	 value Token { Value=load,
      s
   Position=file:/Users/headius/projects/jruby/lib/jruby.jar!/
   jruby/kernel.rb:6}
   shift	from state 2 to 33

                           You will never need this.
   push	 state 33	 value Token { Value=load, Position=file:/Users/
   headius/projects/jruby/lib/jruby.jar!/jruby/kernel.rb:6}
   lex	 tate 33	 reading tSTRING_BEG	 value Token { Value=',
      s
   Position=file:/Users/headius/projects/jruby/lib/jruby.jar!/
   jruby/kernel.rb:6}
   reduce	 tate 33	 uncover 2	
          s                  rule (487) operation : tIDENTIFIER
   goto	 from state 2 to 62
   push	 state 62	 value Token { Value=load, Position=file:/Users/
   headius/projects/jruby/lib/jruby.jar!/jruby/kernel.rb:6}
   reduce	 tate 62	 uncover 62	 rule (252) $$6 :
          s



Friday, November 4, 2011
public class RubyYaccLexer {
            public static final Encoding UTF8_ENCODING = UTF8Encoding.INSTANCE;
            public static final Encoding USASCII_ENCODING = USASCIIEncoding.INSTANCE;
            public static final Encoding ASCII8BIT_ENCODING = ASCIIEncoding.INSTANCE;
            
            private static ByteList END_MARKER = new ByteList(new byte[] {'_', 'E', 'N', 'D', '_', '_'});
            private static ByteList BEGIN_DOC_MARKER = new ByteList(new byte[] {'b', 'e', 'g', 'i', 'n'});
            private static ByteList END_DOC_MARKER = new ByteList(new byte[] {'e', 'n', 'd'});
            private static final HashMap<String, Keyword> map;

            static {
                map = new HashMap<String, Keyword>();

                map.put("end", Keyword.END);
                map.put("else", Keyword.ELSE);
                map.put("case", Keyword.CASE);
                map.put("ensure", Keyword.ENSURE);
                map.put("module", Keyword.MODULE);
                map.put("elsif", Keyword.ELSIF);
                map.put("def", Keyword.DEF);
                map.put("rescue", Keyword.RESCUE);
                map.put("not", Keyword.NOT);
                map.put("then", Keyword.THEN);
                map.put("yield", Keyword.YIELD);
                map.put("for", Keyword.FOR);
                map.put("self", Keyword.SELF);
                map.put("false", Keyword.FALSE);




Friday, November 4, 2011
    public enum Keyword {
                   END ("end", Tokens.kEND, Tokens.kEND, LexState.EXPR_END),
                   ELSE ("else", Tokens.kELSE, Tokens.kELSE, LexState.EXPR_BEG),
                   CASE ("case", Tokens.kCASE, Tokens.kCASE, LexState.EXPR_BEG),
                   ENSURE ("ensure", Tokens.kENSURE, Tokens.kENSURE, LexState.EXPR_BEG),
                   MODULE ("module", Tokens.kMODULE, Tokens.kMODULE, LexState.EXPR_BEG),
                   ELSIF ("elsif", Tokens.kELSIF, Tokens.kELSIF, LexState.EXPR_BEG),
                   DEF ("def", Tokens.kDEF, Tokens.kDEF, LexState.EXPR_FNAME),
                   RESCUE ("rescue", Tokens.kRESCUE, Tokens.kRESCUE_MOD, LexState.EXPR_MID),
                   NOT ("not", Tokens.kNOT, Tokens.kNOT, LexState.EXPR_BEG),
                   THEN ("then", Tokens.kTHEN, Tokens.kTHEN, LexState.EXPR_BEG),
                   YIELD ("yield", Tokens.kYIELD, Tokens.kYIELD, LexState.EXPR_ARG),
                   FOR ("for", Tokens.kFOR, Tokens.kFOR, LexState.EXPR_BEG),
                   SELF ("self", Tokens.kSELF, Tokens.kSELF, LexState.EXPR_END),
                   FALSE ("false", Tokens.kFALSE, Tokens.kFALSE, LexState.EXPR_END),
                   RETRY ("retry", Tokens.kRETRY, Tokens.kRETRY, LexState.EXPR_END),
                   RETURN ("return", Tokens.kRETURN, Tokens.kRETURN, LexState.EXPR_MID),
                   TRUE ("true", Tokens.kTRUE, Tokens.kTRUE, LexState.EXPR_END),
                   IF ("if", Tokens.kIF, Tokens.kIF_MOD, LexState.EXPR_BEG),
                   DEFINED_P ("defined?", Tokens.kDEFINED, Tokens.kDEFINED, LexState.EXPR_ARG),




Friday, November 4, 2011
    private int yylex() throws IOException {
          int c;
          boolean spaceSeen = false;
          boolean commandState;
          
          if (lex_strterm != null) {
              int tok = lex_strterm.parseString(this, src);
              if (tok == Tokens.tSTRING_END || tok == Tokens.tREGEXP_END) {
                  lex_strterm = null;
                  setState(LexState.EXPR_END);
              }

              return tok;
          }

          commandState = commandStart;
          commandStart = false;

          loop: for(;;) {
              c = src.read();
              switch(c) {




Friday, November 4, 2011
            case '<':
                          return   lessThan(spaceSeen);
                      case '>':
                          return   greaterThan();
                      case '"':
                          return   doubleQuote();
                      case '`':
                          return   backtick(commandState);
                      case ''':
                          return   singleQuote();
                      case '?':
                          return   questionMark();
                      case '&':
                          return   ampersand(spaceSeen);
                      case '|':
                          return   pipe();
                      case '+':
                          return   plus(spaceSeen);



Friday, November 4, 2011
    private int lessThan(boolean spaceSeen) throws IOException {
                int c = src.read();
                if (c == '<' && lex_state != LexState.EXPR_DOT && lex_state !=
        LexState.EXPR_CLASS &&
                        !isEND() && (!isARG() || spaceSeen)) {
                    int tok = hereDocumentIdentifier();
                    
                    if (tok != 0) return tok;
                }
                
                determineExpressionState();
                
                switch (c) {
                case '=':
                    if ((c = src.read()) == '>') {
                        yaccValue = new Token("<=>", getPosition());
                        return Tokens.tCMP;




Friday, November 4, 2011
%%
      program       : {
                        lexer.setState(LexState.EXPR_BEG);
                        support.initTopLocalVariables();
                    } top_compstmt {
        // ENEBO: Removed !compile_for_eval which probably is to reduce
      warnings
                        if ($2 != null) {
                            /* last expression should not be void */
                            if ($2 instanceof BlockNode) {
                                support.checkUselessStatement
      ($<BlockNode>2.getLast());
                            } else {
                                support.checkUselessStatement($2);
                            }
                        }
                        support.getResult().setAST(support.addRootNode
      ($2, support.getPosition($2)));
                    }




Friday, November 4, 2011
stmt            : kALIAS fitem {
                            lexer.setState(LexState.EXPR_FNAME);
                        } fitem {
                            $$ = support.newAlias($1.getPosition(), $2, $4);
                        }
                        | kALIAS tGVAR tGVAR {
                            $$ = new VAliasNode($1.getPosition(), (String)
        $2.getValue(), (String) $3.getValue());
                        }
                        | kALIAS tGVAR tBACK_REF {
                            $$ = new VAliasNode($1.getPosition(), (String)
        $2.getValue(), "$" + $<BackRefNode>3.getType());
                        }
                        | kALIAS tGVAR tNTH_REF {
                            support.yyerror("can't make alias for the number
        variables");
                        }
                        | kUNDEF undef_list {
                            $$ = $2;
                        }
                        | stmt kIF_MOD expr_value {
                            $$ = new IfNode(support.getPosition($1),
        support.getConditionNode($3), $1, null);
                        }



Friday, November 4, 2011
  public Object yyparse (RubyYaccLexer yyLex) throws java.io.IOException {
           if (yyMax <= 0) yyMax = 256;"" " // initial size
           int yyState = 0, yyStates[] = new int[yyMax];" // state stack
           Object yyVal = null, yyVals[] = new Object[yyMax];" // value stack
           int yyToken = -1;" " " " " // current input
           int yyErrorFlag = 0;" " " " // #tokens to shift

           yyLoop: for (int yyTop = 0;; ++ yyTop) {
             if (yyTop >= yyStates.length) {" " " // dynamically increase
               int[] i = new int[yyStates.length+yyMax];
               System.arraycopy(yyStates, 0, i, 0, yyStates.length);
               yyStates = i;
               Object[] o = new Object[yyVals.length+yyMax];
               System.arraycopy(yyVals, 0, o, 0, yyVals.length);
               yyVals = o;
             }
             yyStates[yyTop] = yyState;
             yyVals[yyTop] = yyVal;
             if (yydebug != null) yydebug.push(yyState, yyVal);




Friday, November 4, 2011
        if (state == null) {
                    yyVal = yyDefault(yyV > yyTop ? null : yyVals[yyV]);
                } else {
                    yyVal = state.execute(support, lexer, yyVal, yyVals, yyTop);
                }




Friday, November 4, 2011
states[23] = new ParserState() {
         public Object execute(ParserSupport support, RubyYaccLexer lexer, Object
       yyVal, Object[] yyVals, int yyTop) {
                           yyVal = new IfNode(support.getPosition(((Node)yyVals
       [-2+yyTop])), support.getConditionNode(((Node)yyVals[0+yyTop])), ((Node)
       yyVals[-2+yyTop]), null);
           return yyVal;
         }
       };
                           Never look at this.
       states[24] = new ParserState() {
         public Object execute(ParserSupport support, RubyYaccLexer lexer, Object
       yyVal, Object[] yyVals, int yyTop) {
                           yyVal = new IfNode(support.getPosition(((Node)yyVals
       [-2+yyTop])), support.getConditionNode(((Node)yyVals[0+yyTop])), null,
       ((Node)yyVals[-2+yyTop]));
           return yyVal;
         }
       };




Friday, November 4, 2011
AST

                    • Interpreted directly
                    • Specialized in places
                    • Large and rich


Friday, November 4, 2011
$ ast -e "a = true; if a; 2; else; 3; end"
       AST:
       RootNode 0
         BlockNode 0
            NewlineNode 0
              LocalAsgnNode:a 0
                TrueNode:true 0
            NewlineNode 0
              IfNode 0
                LocalVarNode:a 0
                NewlineNode 0
                  FixnumNode 0
                NewlineNode 0
                  FixnumNode 0


Friday, November 4, 2011
public class IfNode extends Node {
          private final Node condition;
          private final Node thenBody;
          private final Node elseBody;

          public IfNode(ISourcePosition position, Node   condition, Node thenBody,
      Node elseBody) {
              super(position);
              
              assert condition != null : "condition is   not null";
      //        assert thenBody != null : "thenBody is   not null";
      //        assert elseBody != null : "elseBody is   not null";
              
              this.condition = condition;
              this.thenBody = thenBody;
              this.elseBody = elseBody;
          }




Friday, November 4, 2011
    @Override
            public IRubyObject interpret(Ruby runtime, ThreadContext context,
        IRubyObject self, Block aBlock) {
                ISourcePosition position = getPosition();

                context.setFile(position.getFile());
                context.setLine(position.getStartLine());

                IRubyObject result =
                     condition.interpret(runtime, context, self, aBlock);
                
                if (result.isTrue()) {
                    return thenBody == null ?
                         runtime.getNil() :
                         thenBody.interpret(runtime, context, self, aBlock);
                } else {
                    return elseBody == null ?
                         runtime.getNil() :
                         elseBody.interpret(runtime, context, self, aBlock);
                }
            }




Friday, November 4, 2011
IR (future work)

                    • Control flow graph
                    • Ruby-specific instruction set
                    • Optimizing compiler
                    • Ruby-level optimizations

Friday, November 4, 2011
jruby -e “1 + 1”




Friday, November 4, 2011
2011-11-04T05:23:09.375-03:00: IR_Printer:
                     instrs:
                     0	 %self = recv_self
                     1	 %block(0:0) = recv_closure
                     2	 file_name(-e)
                     3	 line_num(0)
                     4	 %v_0 = call(+, 1:fixnum, [1:fixnum])
                     5	 return(%v_0)
                   2011-11-04T05:23:09.375-03:00: IR_Printer:
                     live variables:
                       %v_0: 4-5




Friday, November 4, 2011
a = 1; while a < 10; puts a; a += 1; end




Friday, November 4, 2011
2011-11-04T05:25:23.517-03:00: IR_Printer:
                     instrs:
                     0	%self = recv_self
                     1	%block(0:0) = recv_closure
                     2	file_name(-e)
                     3	line_num(0)
                     4	a(0:1) = 1:fixnum
                     5	_LOOP_BEGIN_0:
                     6	%v_1 = call(<, a(0:1), [10:fixnum])
                     7	beq(%v_1, true, _ITER_BEGIN_0)
                     8	%v_0 = nil
                     9	jump _LOOP_END_0
                     10	   _ITER_BEGIN_0:
                     11	   %v_2 = call(puts, %self, [a(0:1)])
                     12	   %v_3 = call(+, a(0:1), [1:fixnum])
                     13	   a(0:1) = copy(%v_3)
                     14	   %v_0 = copy(%v_3)
                     15	   thread_poll
                     16	   _ITER_END_0:
                     17	   jump _LOOP_BEGIN_0
                     18	   _LOOP_END_0:
                     19	   return(%v_0)
                   2011-11-04T05:25:23.517-03:00: IR_Printer:
                     live variables:
                       %v_0: 8-19
                       %v_1: 6-7
                       %v_3: 12-14
Friday, November 4, 2011
2011-11-04T05:25:23.518-03:00: IRScope: ################## After
                   CFG Linearize##################
                   2011-11-04T05:25:23.518-03:00: IR_Printer:
                   ----------------------------------------
                   2011-11-04T05:25:23.518-03:00: IR_Printer: Method [root]:
                   [script]:-e
                   2011-11-04T05:25:23.518-03:00: IR_Printer:
                   Graph:
                   BB [4:LBL_3]:>[7], <[3]
                   BB [1:LBL_1]:>[8,2]
                   BB [2:LBL_2]:>[3], <[1]
                   BB [7:_LOOP_END_0]:>[8], <[4]
                   BB [8:LBL_4]:<[1,7]
                   BB [3:_LOOP_BEGIN_0]:>[5,4], <[6,2]
                   BB [6:_ITER_END_0]:>[3], <[5]
                   BB [5:_ITER_BEGIN_0]:>[6], <[3]




Friday, November 4, 2011
2011-11-04T05:25:23.517-03:00: IR_Printer:
                     instrs:
                     0	%self = recv_self
                     1	%block(0:0) = recv_closure
                     2	file_name(-e)
                     3	line_num(0)
                     4	a(0:1) = 1:fixnum
                     5	_LOOP_BEGIN_0:
                     6	%v_1 = call(<, a(0:1), [10:fixnum])
                     7	beq(%v_1, true, _ITER_BEGIN_0)
                     8	%v_0 = nil
                     9	jump _LOOP_END_0
                     10	   _ITER_BEGIN_0:
                     11	   %v_2 = call(puts, %self, [a(0:1)])
                     12	   %v_3 = call(+, a(0:1), [1:fixnum])
                     13	   a(0:1) = copy(%v_3)
                     14	   %v_0 = copy(%v_3)
                     15	   thread_poll
                     16	   _ITER_END_0:
                     17	   jump _LOOP_BEGIN_0
                     18	   _LOOP_END_0:
                     19	   return(%v_0)
                   2011-11-04T05:25:23.517-03:00: IR_Printer:
                     live variables:
                       %v_0: 8-19
                       %v_1: 6-7
                       %v_3: 12-14
Friday, November 4, 2011
2011-11-04T05:25:23.518-03:00: IR_Printer:
                   Instructions:
                   BB [4:LBL_3]
                   	 %v_0 = nil
                   BB [1:LBL_1]
                   BB [2:LBL_2]
                   	 %self = recv_self
                   	 %block(0:0) = recv_closure
                   	 file_name(-e)
                   	 line_num(0)
                   	 a(0:1) = 1:fixnum
                   BB [7:_LOOP_END_0]
                   	 return(%v_0)
                   BB [8:LBL_4]
                   	 return(nil)



Friday, November 4, 2011
Core classes

                    • Mostly Java-based
                    • Leverage JDK where possible
                    • Work around JDK where necessary
                    • Use Ruby when possible

Friday, November 4, 2011
@JRubyClass(name="Fixnum", parent="Integer", include="Precision")
        public class RubyFixnum extends RubyInteger {
            
            public static RubyClass createFixnumClass(Ruby runtime) {
                RubyClass fixnum = runtime.defineClass("Fixnum", runtime.getInteger(),
                        ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);




Friday, November 4, 2011
    @JRubyMethod(name = "+")
            public IRubyObject op_plus(ThreadContext context, IRubyObject other) {
                if (other instanceof RubyFixnum) {
                    return addFixnum(context, (RubyFixnum)other);
                }
                return addOther(context, other);
            }




Friday, November 4, 2011
    private IRubyObject addFixnum(ThreadContext context, RubyFixnum other) {
               long otherValue = other.value;
               long result = value + otherValue;
               if (additionOverflowed(value, otherValue, result)) {
                   return addAsBignum(context, other);
               }
               return newFixnum(context.getRuntime(), result);
           }




Friday, November 4, 2011
Compiler

                    • AST-walking
                    • ASM bytecode library
                    • Minimal optimizations
                    • Invokedynamic really helps
                    • IR offers new opportunities

Friday, November 4, 2011
jruby --bytecode -e “1 + 1”




Friday, November 4, 2011
ALOAD 0
                    INVOKEVIRTUAL ruby/__dash_e__.getCallSite0
                    ALOAD 1
                    ALOAD 2
                    ALOAD 1
                    GETFIELD org/jruby/runtime/ThreadContext.runtime
                    INVOKESTATIC org/jruby/RubyFixnum.one
                    LDC 1
                    INVOKEVIRTUAL org/jruby/runtime/CallSite.call
                    ARETURN




Friday, November 4, 2011
public class ASTCompiler {
            private boolean isAtRoot = true;

            public void compileBody(Node node, BodyCompiler context, boolean expr) {
                Node oldBodyNode = currentBodyNode;
                currentBodyNode = node;
                compile(node, context, expr);
                currentBodyNode = oldBodyNode;
            }
            
            public void compile(Node node, BodyCompiler context, boolean expr) {
                if (node == null) {
                    if (expr) context.loadNil();
                    return;
                }
                switch (node.getNodeType()) {
                    case ALIASNODE:
                        compileAlias((AliasNode) node, context, expr);
                        break;
                    case ANDNODE:
                        compileAnd(node, context, expr);
                        break;




Friday, November 4, 2011
    public void compileIf(Node node, BodyCompiler context, final boolean expr) {
                final IfNode ifNode = (IfNode) node;

                // optimizations if we know ahead of time it will always be true or false
                Node actualCondition = ifNode.getCondition();
                while (actualCondition instanceof NewlineNode) {
                    actualCondition = ((NewlineNode)actualCondition).getNextNode();
                }

                if (actualCondition.getNodeType().alwaysTrue()) {
                    // compile condition as non-expr and just compile "then" body
                    compile(actualCondition, context, false);
                    compile(ifNode.getThenBody(), context, expr);
                } else if (actualCondition.getNodeType().alwaysFalse()) {
                    // always false or nil
                    compile(ifNode.getElseBody(), context, expr);
                } else {




Friday, November 4, 2011
            BranchCallback trueCallback = new BranchCallback() {
                         public void branch(BodyCompiler context) {
                             if (ifNode.getThenBody() != null) {
                                 compile(ifNode.getThenBody(), context, expr);
                             } else {
                                 if (expr) context.loadNil();
                             }
                         }
                     };

                     BranchCallback falseCallback = new BranchCallback() {
                         public void branch(BodyCompiler context) {
                             if (ifNode.getElseBody() != null) {
                                 compile(ifNode.getElseBody(), context, expr);
                             } else {
                                 if (expr) context.loadNil();
                             }
                         }
                     };
                     
                     // normal
                     compile(actualCondition, context, true);
                     context.performBooleanBranch(trueCallback, falseCallback);
                 }



Friday, November 4, 2011
public abstract class BaseBodyCompiler implements BodyCompiler {
            protected SkinnyMethodAdapter method;
            protected VariableCompiler variableCompiler;
            protected InvocationCompiler invocationCompiler;
            protected int argParamCount;
            protected Label[] currentLoopLabels;
            protected Label scopeStart = new Label();
            protected Label scopeEnd = new Label();
            protected Label redoJump;
            protected boolean inNestedMethod = false;
            private int lastLine = -1;
            private int lastPositionLine = -1;
            protected StaticScope scope;
            protected ASTInspector inspector;
            protected String methodName;
            protected String rubyName;
            protected StandardASMCompiler script;




Friday, November 4, 2011
    public void performBooleanBranch(BranchCallback trueBranch,
                                               BranchCallback falseBranch) {
                 Label afterJmp = new Label();
                 Label falseJmp = new Label();

                 // call isTrue on the result
                 isTrue();

                 method.ifeq(falseJmp); // EQ == 0 (i.e. false)
                 trueBranch.branch(this);
                 method.go_to(afterJmp);

                 // FIXME: optimize for cases where we have no false branch
                 method.label(falseJmp);
                 falseBranch.branch(this);

                 method.label(afterJmp);
             }




Friday, November 4, 2011
More Demos!
                    • JRuby + JVM flags
                    • JRuby concurrency
                    • Invokedynamic (Java 7)
                    • Redcar Editor
                    • Ruboto (Android)
                    • VisualVM
Friday, November 4, 2011

More Related Content

What's hot

Pragmatic Smalltalk
Pragmatic SmalltalkPragmatic Smalltalk
Pragmatic Smalltalk
ESUG
 
Splash
SplashSplash
Splash
Brendan Eich
 
sete linguagens em sete semanas
sete linguagens em sete semanassete linguagens em sete semanas
sete linguagens em sete semanas
tdc-globalcode
 
The economies of scaling software - Abdel Remani
The economies of scaling software - Abdel RemaniThe economies of scaling software - Abdel Remani
The economies of scaling software - Abdel Remani
jaxconf
 
03/2012 - Popping the gherkin stack
03/2012 - Popping the gherkin stack03/2012 - Popping the gherkin stack
03/2012 - Popping the gherkin stack
daveayan
 
Shell scripting with f
Shell scripting with fShell scripting with f
Shell scripting with f
OnorioCatenacci
 

What's hot (6)

Pragmatic Smalltalk
Pragmatic SmalltalkPragmatic Smalltalk
Pragmatic Smalltalk
 
Splash
SplashSplash
Splash
 
sete linguagens em sete semanas
sete linguagens em sete semanassete linguagens em sete semanas
sete linguagens em sete semanas
 
The economies of scaling software - Abdel Remani
The economies of scaling software - Abdel RemaniThe economies of scaling software - Abdel Remani
The economies of scaling software - Abdel Remani
 
03/2012 - Popping the gherkin stack
03/2012 - Popping the gherkin stack03/2012 - Popping the gherkin stack
03/2012 - Popping the gherkin stack
 
Shell scripting with f
Shell scripting with fShell scripting with f
Shell scripting with f
 

Similar to Building Languages for the JVM - StarTechConf 2011

The Easy Way - Plone Conference 2011
The Easy Way - Plone Conference 2011The Easy Way - Plone Conference 2011
The Easy Way - Plone Conference 2011
Mikko Ohtamaa
 
High quality iOS development
High quality iOS developmentHigh quality iOS development
High quality iOS development
Robin Lu
 
Intro to Micro-frameworks
Intro to Micro-frameworksIntro to Micro-frameworks
Intro to Micro-frameworks
jsmith92
 
Extending rails
Extending railsExtending rails
Extending rails
Blazing Cloud
 
Clouds against the Floods (RubyConfBR2011)
Clouds against the Floods (RubyConfBR2011) Clouds against the Floods (RubyConfBR2011)
Clouds against the Floods (RubyConfBR2011)
Leonardo Borges
 
Tor2web ESC2011
Tor2web ESC2011Tor2web ESC2011
Tor2web ESC2011
Arturo Filastò
 
JUDCon 2011 - Box Grinder
JUDCon 2011 - Box GrinderJUDCon 2011 - Box Grinder
JUDCon 2011 - Box Grinder
Fedora-Fr
 
Are Your Tests Really Helping You?
Are Your Tests Really Helping You?Are Your Tests Really Helping You?
Are Your Tests Really Helping You?
LB Denker
 
Introducing the Ceylon Project - Gavin King presentation at QCon Beijing 2011
Introducing the Ceylon Project - Gavin King presentation at QCon Beijing 2011Introducing the Ceylon Project - Gavin King presentation at QCon Beijing 2011
Introducing the Ceylon Project - Gavin King presentation at QCon Beijing 2011
devstonez
 
Introducing the Ceylon Project
Introducing the Ceylon ProjectIntroducing the Ceylon Project
Introducing the Ceylon Project
Michael Scovetta
 
2011 JavaOne Apache TomEE Java EE 6 Web Profile
2011 JavaOne Apache TomEE Java EE 6 Web Profile2011 JavaOne Apache TomEE Java EE 6 Web Profile
2011 JavaOne Apache TomEE Java EE 6 Web Profile
David Blevins
 
TSSJS 2011 - JRuby
TSSJS 2011 - JRubyTSSJS 2011 - JRuby
TSSJS 2011 - JRuby
Charles Nutter
 
JRuby in The Enterprise
JRuby in The EnterpriseJRuby in The Enterprise
JRuby in The Enterprise
Leonardo Borges
 
Stardog talk-dc-march-17
Stardog talk-dc-march-17Stardog talk-dc-march-17
Stardog talk-dc-march-17
Clark & Parsia LLC
 
ES.next
ES.nextES.next
ES.next
Brendan Eich
 
Ruby Midwest 2010 jRuby by Charles Nutter
Ruby Midwest 2010 jRuby by Charles NutterRuby Midwest 2010 jRuby by Charles Nutter
Ruby Midwest 2010 jRuby by Charles Nutter
Steven Chau
 
Interactive Project Management Workshop
Interactive Project Management WorkshopInteractive Project Management Workshop
Interactive Project Management Workshop
Shelley Simmons
 
Image and Music: Processing plus Pure Data with libpd library
Image and Music: Processing plus Pure Data with libpd libraryImage and Music: Processing plus Pure Data with libpd library
Image and Music: Processing plus Pure Data with libpd library
PETER KIRN
 
10 Things you should know about Ruby
10 Things you should know about Ruby10 Things you should know about Ruby
10 Things you should know about Ruby
sikachu
 
Databases -- Have it Your Way (Frederick Cheung)
Databases -- Have it Your Way (Frederick Cheung)Databases -- Have it Your Way (Frederick Cheung)
Databases -- Have it Your Way (Frederick Cheung)
Skills Matter
 

Similar to Building Languages for the JVM - StarTechConf 2011 (20)

The Easy Way - Plone Conference 2011
The Easy Way - Plone Conference 2011The Easy Way - Plone Conference 2011
The Easy Way - Plone Conference 2011
 
High quality iOS development
High quality iOS developmentHigh quality iOS development
High quality iOS development
 
Intro to Micro-frameworks
Intro to Micro-frameworksIntro to Micro-frameworks
Intro to Micro-frameworks
 
Extending rails
Extending railsExtending rails
Extending rails
 
Clouds against the Floods (RubyConfBR2011)
Clouds against the Floods (RubyConfBR2011) Clouds against the Floods (RubyConfBR2011)
Clouds against the Floods (RubyConfBR2011)
 
Tor2web ESC2011
Tor2web ESC2011Tor2web ESC2011
Tor2web ESC2011
 
JUDCon 2011 - Box Grinder
JUDCon 2011 - Box GrinderJUDCon 2011 - Box Grinder
JUDCon 2011 - Box Grinder
 
Are Your Tests Really Helping You?
Are Your Tests Really Helping You?Are Your Tests Really Helping You?
Are Your Tests Really Helping You?
 
Introducing the Ceylon Project - Gavin King presentation at QCon Beijing 2011
Introducing the Ceylon Project - Gavin King presentation at QCon Beijing 2011Introducing the Ceylon Project - Gavin King presentation at QCon Beijing 2011
Introducing the Ceylon Project - Gavin King presentation at QCon Beijing 2011
 
Introducing the Ceylon Project
Introducing the Ceylon ProjectIntroducing the Ceylon Project
Introducing the Ceylon Project
 
2011 JavaOne Apache TomEE Java EE 6 Web Profile
2011 JavaOne Apache TomEE Java EE 6 Web Profile2011 JavaOne Apache TomEE Java EE 6 Web Profile
2011 JavaOne Apache TomEE Java EE 6 Web Profile
 
TSSJS 2011 - JRuby
TSSJS 2011 - JRubyTSSJS 2011 - JRuby
TSSJS 2011 - JRuby
 
JRuby in The Enterprise
JRuby in The EnterpriseJRuby in The Enterprise
JRuby in The Enterprise
 
Stardog talk-dc-march-17
Stardog talk-dc-march-17Stardog talk-dc-march-17
Stardog talk-dc-march-17
 
ES.next
ES.nextES.next
ES.next
 
Ruby Midwest 2010 jRuby by Charles Nutter
Ruby Midwest 2010 jRuby by Charles NutterRuby Midwest 2010 jRuby by Charles Nutter
Ruby Midwest 2010 jRuby by Charles Nutter
 
Interactive Project Management Workshop
Interactive Project Management WorkshopInteractive Project Management Workshop
Interactive Project Management Workshop
 
Image and Music: Processing plus Pure Data with libpd library
Image and Music: Processing plus Pure Data with libpd libraryImage and Music: Processing plus Pure Data with libpd library
Image and Music: Processing plus Pure Data with libpd library
 
10 Things you should know about Ruby
10 Things you should know about Ruby10 Things you should know about Ruby
10 Things you should know about Ruby
 
Databases -- Have it Your Way (Frederick Cheung)
Databases -- Have it Your Way (Frederick Cheung)Databases -- Have it Your Way (Frederick Cheung)
Databases -- Have it Your Way (Frederick Cheung)
 

More from Charles Nutter

The Year of JRuby - RubyC 2018
The Year of JRuby - RubyC 2018The Year of JRuby - RubyC 2018
The Year of JRuby - RubyC 2018
Charles Nutter
 
Down the Rabbit Hole: An Adventure in JVM Wonderland
Down the Rabbit Hole: An Adventure in JVM WonderlandDown the Rabbit Hole: An Adventure in JVM Wonderland
Down the Rabbit Hole: An Adventure in JVM Wonderland
Charles Nutter
 
Ruby Performance - The Last Mile - RubyConf India 2016
Ruby Performance - The Last Mile - RubyConf India 2016Ruby Performance - The Last Mile - RubyConf India 2016
Ruby Performance - The Last Mile - RubyConf India 2016
Charles Nutter
 
JRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVMJRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVM
Charles Nutter
 
JRuby and Invokedynamic - Japan JUG 2015
JRuby and Invokedynamic - Japan JUG 2015JRuby and Invokedynamic - Japan JUG 2015
JRuby and Invokedynamic - Japan JUG 2015
Charles Nutter
 
JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015
Charles Nutter
 
Fast as C: How to Write Really Terrible Java
Fast as C: How to Write Really Terrible JavaFast as C: How to Write Really Terrible Java
Fast as C: How to Write Really Terrible Java
Charles Nutter
 
Open Source Software Needs You!
Open Source Software Needs You!Open Source Software Needs You!
Open Source Software Needs You!
Charles Nutter
 
InvokeBinder: Fluent Programming for Method Handles
InvokeBinder: Fluent Programming for Method HandlesInvokeBinder: Fluent Programming for Method Handles
InvokeBinder: Fluent Programming for Method Handles
Charles Nutter
 
Over 9000: JRuby in 2015
Over 9000: JRuby in 2015Over 9000: JRuby in 2015
Over 9000: JRuby in 2015
Charles Nutter
 
Doing Open Source the Right Way
Doing Open Source the Right WayDoing Open Source the Right Way
Doing Open Source the Right Way
Charles Nutter
 
JRuby: The Hard Parts
JRuby: The Hard PartsJRuby: The Hard Parts
JRuby: The Hard Parts
Charles Nutter
 
Bringing Concurrency to Ruby - RubyConf India 2014
Bringing Concurrency to Ruby - RubyConf India 2014Bringing Concurrency to Ruby - RubyConf India 2014
Bringing Concurrency to Ruby - RubyConf India 2014
Charles Nutter
 
Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013
Charles Nutter
 
Beyond JVM - YOW! Brisbane 2013
Beyond JVM - YOW! Brisbane 2013Beyond JVM - YOW! Brisbane 2013
Beyond JVM - YOW! Brisbane 2013
Charles Nutter
 
Beyond JVM - YOW Melbourne 2013
Beyond JVM - YOW Melbourne 2013Beyond JVM - YOW Melbourne 2013
Beyond JVM - YOW Melbourne 2013
Charles Nutter
 
Down the Rabbit Hole
Down the Rabbit HoleDown the Rabbit Hole
Down the Rabbit Hole
Charles Nutter
 
The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013
Charles Nutter
 
High Performance Ruby - E4E Conference 2013
High Performance Ruby - E4E Conference 2013High Performance Ruby - E4E Conference 2013
High Performance Ruby - E4E Conference 2013
Charles Nutter
 
Invokedynamic in 45 Minutes
Invokedynamic in 45 MinutesInvokedynamic in 45 Minutes
Invokedynamic in 45 Minutes
Charles Nutter
 

More from Charles Nutter (20)

The Year of JRuby - RubyC 2018
The Year of JRuby - RubyC 2018The Year of JRuby - RubyC 2018
The Year of JRuby - RubyC 2018
 
Down the Rabbit Hole: An Adventure in JVM Wonderland
Down the Rabbit Hole: An Adventure in JVM WonderlandDown the Rabbit Hole: An Adventure in JVM Wonderland
Down the Rabbit Hole: An Adventure in JVM Wonderland
 
Ruby Performance - The Last Mile - RubyConf India 2016
Ruby Performance - The Last Mile - RubyConf India 2016Ruby Performance - The Last Mile - RubyConf India 2016
Ruby Performance - The Last Mile - RubyConf India 2016
 
JRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVMJRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVM
 
JRuby and Invokedynamic - Japan JUG 2015
JRuby and Invokedynamic - Japan JUG 2015JRuby and Invokedynamic - Japan JUG 2015
JRuby and Invokedynamic - Japan JUG 2015
 
JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015
 
Fast as C: How to Write Really Terrible Java
Fast as C: How to Write Really Terrible JavaFast as C: How to Write Really Terrible Java
Fast as C: How to Write Really Terrible Java
 
Open Source Software Needs You!
Open Source Software Needs You!Open Source Software Needs You!
Open Source Software Needs You!
 
InvokeBinder: Fluent Programming for Method Handles
InvokeBinder: Fluent Programming for Method HandlesInvokeBinder: Fluent Programming for Method Handles
InvokeBinder: Fluent Programming for Method Handles
 
Over 9000: JRuby in 2015
Over 9000: JRuby in 2015Over 9000: JRuby in 2015
Over 9000: JRuby in 2015
 
Doing Open Source the Right Way
Doing Open Source the Right WayDoing Open Source the Right Way
Doing Open Source the Right Way
 
JRuby: The Hard Parts
JRuby: The Hard PartsJRuby: The Hard Parts
JRuby: The Hard Parts
 
Bringing Concurrency to Ruby - RubyConf India 2014
Bringing Concurrency to Ruby - RubyConf India 2014Bringing Concurrency to Ruby - RubyConf India 2014
Bringing Concurrency to Ruby - RubyConf India 2014
 
Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013Beyond JVM - YOW! Sydney 2013
Beyond JVM - YOW! Sydney 2013
 
Beyond JVM - YOW! Brisbane 2013
Beyond JVM - YOW! Brisbane 2013Beyond JVM - YOW! Brisbane 2013
Beyond JVM - YOW! Brisbane 2013
 
Beyond JVM - YOW Melbourne 2013
Beyond JVM - YOW Melbourne 2013Beyond JVM - YOW Melbourne 2013
Beyond JVM - YOW Melbourne 2013
 
Down the Rabbit Hole
Down the Rabbit HoleDown the Rabbit Hole
Down the Rabbit Hole
 
The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013
 
High Performance Ruby - E4E Conference 2013
High Performance Ruby - E4E Conference 2013High Performance Ruby - E4E Conference 2013
High Performance Ruby - E4E Conference 2013
 
Invokedynamic in 45 Minutes
Invokedynamic in 45 MinutesInvokedynamic in 45 Minutes
Invokedynamic in 45 Minutes
 

Recently uploaded

Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
SOFTTECHHUB
 
How to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For FlutterHow to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For Flutter
Daiki Mogmet Ito
 
Presentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of GermanyPresentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of Germany
innovationoecd
 
Microsoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdfMicrosoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdf
Uni Systems S.M.S.A.
 
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AIEnchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Vladimir Iglovikov, Ph.D.
 
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
SOFTTECHHUB
 
Introduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - CybersecurityIntroduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - Cybersecurity
mikeeftimakis1
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
KatiaHIMEUR1
 
Mind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AIMind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AI
Kumud Singh
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
Neo4j
 
20240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 202420240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 2024
Matthew Sinclair
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems S.M.S.A.
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
Safe Software
 
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
名前 です男
 
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Speck&Tech
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
Aftab Hussain
 
Introducing Milvus Lite: Easy-to-Install, Easy-to-Use vector database for you...
Introducing Milvus Lite: Easy-to-Install, Easy-to-Use vector database for you...Introducing Milvus Lite: Easy-to-Install, Easy-to-Use vector database for you...
Introducing Milvus Lite: Easy-to-Install, Easy-to-Use vector database for you...
Zilliz
 
20240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 202420240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 2024
Matthew Sinclair
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Paige Cruz
 
Full-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalizationFull-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalization
Zilliz
 

Recently uploaded (20)

Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
 
How to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For FlutterHow to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For Flutter
 
Presentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of GermanyPresentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of Germany
 
Microsoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdfMicrosoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdf
 
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AIEnchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
 
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
 
Introduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - CybersecurityIntroduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - Cybersecurity
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
 
Mind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AIMind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AI
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
 
20240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 202420240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 2024
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
 
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
 
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
 
Introducing Milvus Lite: Easy-to-Install, Easy-to-Use vector database for you...
Introducing Milvus Lite: Easy-to-Install, Easy-to-Use vector database for you...Introducing Milvus Lite: Easy-to-Install, Easy-to-Use vector database for you...
Introducing Milvus Lite: Easy-to-Install, Easy-to-Use vector database for you...
 
20240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 202420240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 2024
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
 
Full-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalizationFull-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalization
 

Building Languages for the JVM - StarTechConf 2011

  • 1. Building Languages for the JVM Charles Oliver Nutter Friday, November 4, 2011
  • 2. Me • Charles Oliver Nutter • JRuby and JVM guy • “headius” on most services • headius@headius.com Friday, November 4, 2011
  • 3. Who Was I? • Java EE architect • Successfully! • Never wrote a parser • Never wrote a compiler • But I wanted to learn how... Friday, November 4, 2011
  • 4. You • Java? • Ruby? • Python? • C#? • Other? Friday, November 4, 2011
  • 5. Why Create Languages? • Nothing is perfect • New problems need new solutions • Language design can be fun • Fame and fortune? • Not really. Friday, November 4, 2011
  • 6. Why Impl a Language? • To learn it? • Sort of... • To learn the target platform • Definitely! • Fame and fortune? • Well...getting there... Friday, November 4, 2011
  • 7. Challenges • Community • Platform • Specifications • Resources Friday, November 4, 2011
  • 8. Community • Investment in status quo • Afraid to stand out • Known quantities • Everything else sucks • Gotta get paid! Friday, November 4, 2011
  • 9. Platform • Matching language semantics • JVM designed around Java • JVM hides underlying platform • Challenging to use • Not bad...C/++ would be way worse • Community may hate it ;-) Friday, November 4, 2011
  • 10. Specifications • Incomplete • Ruby had none for years • ...and no complete test suites • Difficult to implement • Low level features • Single-implementation quirks • Hard or impossible to optimize Friday, November 4, 2011
  • 11. Resources • You gotta eat • Not much money in language work • Some parts are hard • OSS is a necessity Friday, November 4, 2011
  • 12. Why JVM? • Because I am lazy • Because VMs are *hard* • Because I can’t be awesome at everything Friday, November 4, 2011
  • 13. Ok, Why Really? • Cross-platform • Libraries • Languages • Memory management • Tools • OSS Friday, November 4, 2011
  • 14. Cross-platform • OpenJDK: Linux, Windows, Solaris, OS X, xBSD • J9: Linux, zLinux, AS/400, ... • HP: OpenVMS, HP/UX, ... • Dalvik (Android): Linux on ARM, x86 Friday, November 4, 2011
  • 15. Libraries • For any need, a dozen libraries • And a couple of them are good! • Cross-platform • Leading edge Friday, November 4, 2011
  • 16. Selection of languages • Java • Scala • Clojure • JRuby • Mirah • Jython, Groovy, Fantom, Kotlin, Ceylon, ... Friday, November 4, 2011
  • 17. Memory management • Best GCs in the world • Fastest object allocation • Safe escape hatches like NIO Friday, November 4, 2011
  • 18. Tools • Debugging • Profiling • Monitoring • JVM internals Friday, November 4, 2011
  • 19. Open source? • FOSS reference impl (OpenJDK) • Mostly OSS libraries • Heavy OSS culture • Strong OSS influence in OpenJDK core Friday, November 4, 2011
  • 20. Case Study: JRuby Friday, November 4, 2011
  • 21. Ruby on the JVM • All of Ruby’s power and beauty • Solid VM underneath • “Just another JVM language” Friday, November 4, 2011
  • 22. JVM Language • Full interop with Java • Tricky to do... • Very rewarding for 99% case • VM concerns solved • No need to write a GC • No need to write a JIT • ...oh, but wait... Friday, November 4, 2011
  • 23. More than a JVM language • Use native code where JDK fails us • Paper over ugly bits like CLASSPATH • Matching Ruby semantics exactly* • Push JVM forward too! Friday, November 4, 2011
  • 24. Playing with JRuby • Simple IRB demo • JRuby on Rails - see Jano’s talk tomorrow • JRuby performance • PotC (???) Friday, November 4, 2011
  • 25. How did we do it? Friday, November 4, 2011
  • 26. JRuby Architecture • Parser • Abstract Syntax Tree (AST) • Intermediate Representation (IR) • Core classes • Compiler Friday, November 4, 2011
  • 27. Parser • Port of MRI’s Bison grammar • “Jay” parser generator for Java • Hand-written lexer • Nearly as fast as the C version • ...once it gets going Friday, November 4, 2011
  • 28. system ~/projects/jruby $ jruby -y -e "1 + 1" push state 0 value null reduce tate 0 uncover 0 s rule (1) $$1 : goto from state 0 to 2 push state 2 value null lex tate 2 reading tIDENTIFIER value Token { Value=load, s Position=file:/Users/headius/projects/jruby/lib/jruby.jar!/ jruby/kernel.rb:6} shift from state 2 to 33 push state 33 value Token { Value=load, Position=file:/Users/ headius/projects/jruby/lib/jruby.jar!/jruby/kernel.rb:6} lex tate 33 reading tSTRING_BEG value Token { Value=', s Position=file:/Users/headius/projects/jruby/lib/jruby.jar!/ jruby/kernel.rb:6} reduce tate 33 uncover 2 s rule (487) operation : tIDENTIFIER goto from state 2 to 62 push state 62 value Token { Value=load, Position=file:/Users/ headius/projects/jruby/lib/jruby.jar!/jruby/kernel.rb:6} reduce tate 62 uncover 62 rule (252) $$6 : s Friday, November 4, 2011
  • 29. system ~/projects/jruby $ jruby -y -e "1 + 1" push state 0 value null reduce tate 0 uncover 0 s rule (1) $$1 : goto from state 0 to 2 push state 2 value null lex tate 2 reading tIDENTIFIER value Token { Value=load, s Position=file:/Users/headius/projects/jruby/lib/jruby.jar!/ jruby/kernel.rb:6} shift from state 2 to 33 You will never need this. push state 33 value Token { Value=load, Position=file:/Users/ headius/projects/jruby/lib/jruby.jar!/jruby/kernel.rb:6} lex tate 33 reading tSTRING_BEG value Token { Value=', s Position=file:/Users/headius/projects/jruby/lib/jruby.jar!/ jruby/kernel.rb:6} reduce tate 33 uncover 2 s rule (487) operation : tIDENTIFIER goto from state 2 to 62 push state 62 value Token { Value=load, Position=file:/Users/ headius/projects/jruby/lib/jruby.jar!/jruby/kernel.rb:6} reduce tate 62 uncover 62 rule (252) $$6 : s Friday, November 4, 2011
  • 30. public class RubyYaccLexer {     public static final Encoding UTF8_ENCODING = UTF8Encoding.INSTANCE;     public static final Encoding USASCII_ENCODING = USASCIIEncoding.INSTANCE;     public static final Encoding ASCII8BIT_ENCODING = ASCIIEncoding.INSTANCE;          private static ByteList END_MARKER = new ByteList(new byte[] {'_', 'E', 'N', 'D', '_', '_'});     private static ByteList BEGIN_DOC_MARKER = new ByteList(new byte[] {'b', 'e', 'g', 'i', 'n'});     private static ByteList END_DOC_MARKER = new ByteList(new byte[] {'e', 'n', 'd'});     private static final HashMap<String, Keyword> map;     static {         map = new HashMap<String, Keyword>();         map.put("end", Keyword.END);         map.put("else", Keyword.ELSE);         map.put("case", Keyword.CASE);         map.put("ensure", Keyword.ENSURE);         map.put("module", Keyword.MODULE);         map.put("elsif", Keyword.ELSIF);         map.put("def", Keyword.DEF);         map.put("rescue", Keyword.RESCUE);         map.put("not", Keyword.NOT);         map.put("then", Keyword.THEN);         map.put("yield", Keyword.YIELD);         map.put("for", Keyword.FOR);         map.put("self", Keyword.SELF);         map.put("false", Keyword.FALSE); Friday, November 4, 2011
  • 31.     public enum Keyword {         END ("end", Tokens.kEND, Tokens.kEND, LexState.EXPR_END),         ELSE ("else", Tokens.kELSE, Tokens.kELSE, LexState.EXPR_BEG),         CASE ("case", Tokens.kCASE, Tokens.kCASE, LexState.EXPR_BEG),         ENSURE ("ensure", Tokens.kENSURE, Tokens.kENSURE, LexState.EXPR_BEG),         MODULE ("module", Tokens.kMODULE, Tokens.kMODULE, LexState.EXPR_BEG),         ELSIF ("elsif", Tokens.kELSIF, Tokens.kELSIF, LexState.EXPR_BEG),         DEF ("def", Tokens.kDEF, Tokens.kDEF, LexState.EXPR_FNAME),         RESCUE ("rescue", Tokens.kRESCUE, Tokens.kRESCUE_MOD, LexState.EXPR_MID),         NOT ("not", Tokens.kNOT, Tokens.kNOT, LexState.EXPR_BEG),         THEN ("then", Tokens.kTHEN, Tokens.kTHEN, LexState.EXPR_BEG),         YIELD ("yield", Tokens.kYIELD, Tokens.kYIELD, LexState.EXPR_ARG),         FOR ("for", Tokens.kFOR, Tokens.kFOR, LexState.EXPR_BEG),         SELF ("self", Tokens.kSELF, Tokens.kSELF, LexState.EXPR_END),         FALSE ("false", Tokens.kFALSE, Tokens.kFALSE, LexState.EXPR_END),         RETRY ("retry", Tokens.kRETRY, Tokens.kRETRY, LexState.EXPR_END),         RETURN ("return", Tokens.kRETURN, Tokens.kRETURN, LexState.EXPR_MID),         TRUE ("true", Tokens.kTRUE, Tokens.kTRUE, LexState.EXPR_END),         IF ("if", Tokens.kIF, Tokens.kIF_MOD, LexState.EXPR_BEG),         DEFINED_P ("defined?", Tokens.kDEFINED, Tokens.kDEFINED, LexState.EXPR_ARG), Friday, November 4, 2011
  • 32.     private int yylex() throws IOException {         int c;         boolean spaceSeen = false;         boolean commandState;                  if (lex_strterm != null) {             int tok = lex_strterm.parseString(this, src);             if (tok == Tokens.tSTRING_END || tok == Tokens.tREGEXP_END) {                 lex_strterm = null;                 setState(LexState.EXPR_END);             }             return tok;         }         commandState = commandStart;         commandStart = false;         loop: for(;;) {             c = src.read();             switch(c) { Friday, November 4, 2011
  • 33.             case '<':                 return lessThan(spaceSeen);             case '>':                 return greaterThan();             case '"':                 return doubleQuote();             case '`':                 return backtick(commandState);             case ''':                 return singleQuote();             case '?':                 return questionMark();             case '&':                 return ampersand(spaceSeen);             case '|':                 return pipe();             case '+':                 return plus(spaceSeen); Friday, November 4, 2011
  • 34.     private int lessThan(boolean spaceSeen) throws IOException {         int c = src.read();         if (c == '<' && lex_state != LexState.EXPR_DOT && lex_state != LexState.EXPR_CLASS &&                 !isEND() && (!isARG() || spaceSeen)) {             int tok = hereDocumentIdentifier();                          if (tok != 0) return tok;         }                  determineExpressionState();                  switch (c) {         case '=':             if ((c = src.read()) == '>') {                 yaccValue = new Token("<=>", getPosition());                 return Tokens.tCMP; Friday, November 4, 2011
  • 35. %% program : {                   lexer.setState(LexState.EXPR_BEG);                   support.initTopLocalVariables();               } top_compstmt {   // ENEBO: Removed !compile_for_eval which probably is to reduce warnings                   if ($2 != null) {                       /* last expression should not be void */                       if ($2 instanceof BlockNode) {                           support.checkUselessStatement ($<BlockNode>2.getLast());                       } else {                           support.checkUselessStatement($2);                       }                   }                   support.getResult().setAST(support.addRootNode ($2, support.getPosition($2)));               } Friday, November 4, 2011
  • 36. stmt : kALIAS fitem {                     lexer.setState(LexState.EXPR_FNAME);                 } fitem {                     $$ = support.newAlias($1.getPosition(), $2, $4);                 }                 | kALIAS tGVAR tGVAR {                     $$ = new VAliasNode($1.getPosition(), (String) $2.getValue(), (String) $3.getValue());                 }                 | kALIAS tGVAR tBACK_REF {                     $$ = new VAliasNode($1.getPosition(), (String) $2.getValue(), "$" + $<BackRefNode>3.getType());                 }                 | kALIAS tGVAR tNTH_REF {                     support.yyerror("can't make alias for the number variables");                 }                 | kUNDEF undef_list {                     $$ = $2;                 }                 | stmt kIF_MOD expr_value {                     $$ = new IfNode(support.getPosition($1), support.getConditionNode($3), $1, null);                 } Friday, November 4, 2011
  • 37.   public Object yyparse (RubyYaccLexer yyLex) throws java.io.IOException {     if (yyMax <= 0) yyMax = 256;"" " // initial size     int yyState = 0, yyStates[] = new int[yyMax];" // state stack     Object yyVal = null, yyVals[] = new Object[yyMax];" // value stack     int yyToken = -1;" " " " " // current input     int yyErrorFlag = 0;" " " " // #tokens to shift     yyLoop: for (int yyTop = 0;; ++ yyTop) {       if (yyTop >= yyStates.length) {" " " // dynamically increase         int[] i = new int[yyStates.length+yyMax];         System.arraycopy(yyStates, 0, i, 0, yyStates.length);         yyStates = i;         Object[] o = new Object[yyVals.length+yyMax];         System.arraycopy(yyVals, 0, o, 0, yyVals.length);         yyVals = o;       }       yyStates[yyTop] = yyState;       yyVals[yyTop] = yyVal;       if (yydebug != null) yydebug.push(yyState, yyVal); Friday, November 4, 2011
  • 38.         if (state == null) {             yyVal = yyDefault(yyV > yyTop ? null : yyVals[yyV]);         } else {             yyVal = state.execute(support, lexer, yyVal, yyVals, yyTop);         } Friday, November 4, 2011
  • 39. states[23] = new ParserState() {   public Object execute(ParserSupport support, RubyYaccLexer lexer, Object yyVal, Object[] yyVals, int yyTop) {                     yyVal = new IfNode(support.getPosition(((Node)yyVals [-2+yyTop])), support.getConditionNode(((Node)yyVals[0+yyTop])), ((Node) yyVals[-2+yyTop]), null);     return yyVal;   } }; Never look at this. states[24] = new ParserState() {   public Object execute(ParserSupport support, RubyYaccLexer lexer, Object yyVal, Object[] yyVals, int yyTop) {                     yyVal = new IfNode(support.getPosition(((Node)yyVals [-2+yyTop])), support.getConditionNode(((Node)yyVals[0+yyTop])), null, ((Node)yyVals[-2+yyTop]));     return yyVal;   } }; Friday, November 4, 2011
  • 40. AST • Interpreted directly • Specialized in places • Large and rich Friday, November 4, 2011
  • 41. $ ast -e "a = true; if a; 2; else; 3; end" AST: RootNode 0 BlockNode 0 NewlineNode 0 LocalAsgnNode:a 0 TrueNode:true 0 NewlineNode 0 IfNode 0 LocalVarNode:a 0 NewlineNode 0 FixnumNode 0 NewlineNode 0 FixnumNode 0 Friday, November 4, 2011
  • 42. public class IfNode extends Node {     private final Node condition;     private final Node thenBody;     private final Node elseBody;     public IfNode(ISourcePosition position, Node condition, Node thenBody, Node elseBody) {         super(position);                  assert condition != null : "condition is not null"; // assert thenBody != null : "thenBody is not null"; // assert elseBody != null : "elseBody is not null";                  this.condition = condition;         this.thenBody = thenBody;         this.elseBody = elseBody;     } Friday, November 4, 2011
  • 43.     @Override     public IRubyObject interpret(Ruby runtime, ThreadContext context, IRubyObject self, Block aBlock) {         ISourcePosition position = getPosition();         context.setFile(position.getFile());         context.setLine(position.getStartLine());         IRubyObject result = condition.interpret(runtime, context, self, aBlock);                  if (result.isTrue()) {             return thenBody == null ? runtime.getNil() : thenBody.interpret(runtime, context, self, aBlock);         } else {             return elseBody == null ? runtime.getNil() : elseBody.interpret(runtime, context, self, aBlock);         }     } Friday, November 4, 2011
  • 44. IR (future work) • Control flow graph • Ruby-specific instruction set • Optimizing compiler • Ruby-level optimizations Friday, November 4, 2011
  • 45. jruby -e “1 + 1” Friday, November 4, 2011
  • 46. 2011-11-04T05:23:09.375-03:00: IR_Printer: instrs: 0 %self = recv_self 1 %block(0:0) = recv_closure 2 file_name(-e) 3 line_num(0) 4 %v_0 = call(+, 1:fixnum, [1:fixnum]) 5 return(%v_0) 2011-11-04T05:23:09.375-03:00: IR_Printer: live variables: %v_0: 4-5 Friday, November 4, 2011
  • 47. a = 1; while a < 10; puts a; a += 1; end Friday, November 4, 2011
  • 48. 2011-11-04T05:25:23.517-03:00: IR_Printer: instrs: 0 %self = recv_self 1 %block(0:0) = recv_closure 2 file_name(-e) 3 line_num(0) 4 a(0:1) = 1:fixnum 5 _LOOP_BEGIN_0: 6 %v_1 = call(<, a(0:1), [10:fixnum]) 7 beq(%v_1, true, _ITER_BEGIN_0) 8 %v_0 = nil 9 jump _LOOP_END_0 10 _ITER_BEGIN_0: 11 %v_2 = call(puts, %self, [a(0:1)]) 12 %v_3 = call(+, a(0:1), [1:fixnum]) 13 a(0:1) = copy(%v_3) 14 %v_0 = copy(%v_3) 15 thread_poll 16 _ITER_END_0: 17 jump _LOOP_BEGIN_0 18 _LOOP_END_0: 19 return(%v_0) 2011-11-04T05:25:23.517-03:00: IR_Printer: live variables: %v_0: 8-19 %v_1: 6-7 %v_3: 12-14 Friday, November 4, 2011
  • 49. 2011-11-04T05:25:23.518-03:00: IRScope: ################## After CFG Linearize################## 2011-11-04T05:25:23.518-03:00: IR_Printer: ---------------------------------------- 2011-11-04T05:25:23.518-03:00: IR_Printer: Method [root]: [script]:-e 2011-11-04T05:25:23.518-03:00: IR_Printer: Graph: BB [4:LBL_3]:>[7], <[3] BB [1:LBL_1]:>[8,2] BB [2:LBL_2]:>[3], <[1] BB [7:_LOOP_END_0]:>[8], <[4] BB [8:LBL_4]:<[1,7] BB [3:_LOOP_BEGIN_0]:>[5,4], <[6,2] BB [6:_ITER_END_0]:>[3], <[5] BB [5:_ITER_BEGIN_0]:>[6], <[3] Friday, November 4, 2011
  • 50. 2011-11-04T05:25:23.517-03:00: IR_Printer: instrs: 0 %self = recv_self 1 %block(0:0) = recv_closure 2 file_name(-e) 3 line_num(0) 4 a(0:1) = 1:fixnum 5 _LOOP_BEGIN_0: 6 %v_1 = call(<, a(0:1), [10:fixnum]) 7 beq(%v_1, true, _ITER_BEGIN_0) 8 %v_0 = nil 9 jump _LOOP_END_0 10 _ITER_BEGIN_0: 11 %v_2 = call(puts, %self, [a(0:1)]) 12 %v_3 = call(+, a(0:1), [1:fixnum]) 13 a(0:1) = copy(%v_3) 14 %v_0 = copy(%v_3) 15 thread_poll 16 _ITER_END_0: 17 jump _LOOP_BEGIN_0 18 _LOOP_END_0: 19 return(%v_0) 2011-11-04T05:25:23.517-03:00: IR_Printer: live variables: %v_0: 8-19 %v_1: 6-7 %v_3: 12-14 Friday, November 4, 2011
  • 51. 2011-11-04T05:25:23.518-03:00: IR_Printer: Instructions: BB [4:LBL_3] %v_0 = nil BB [1:LBL_1] BB [2:LBL_2] %self = recv_self %block(0:0) = recv_closure file_name(-e) line_num(0) a(0:1) = 1:fixnum BB [7:_LOOP_END_0] return(%v_0) BB [8:LBL_4] return(nil) Friday, November 4, 2011
  • 52. Core classes • Mostly Java-based • Leverage JDK where possible • Work around JDK where necessary • Use Ruby when possible Friday, November 4, 2011
  • 53. @JRubyClass(name="Fixnum", parent="Integer", include="Precision") public class RubyFixnum extends RubyInteger {          public static RubyClass createFixnumClass(Ruby runtime) {         RubyClass fixnum = runtime.defineClass("Fixnum", runtime.getInteger(),                 ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR); Friday, November 4, 2011
  • 54.     @JRubyMethod(name = "+")     public IRubyObject op_plus(ThreadContext context, IRubyObject other) {         if (other instanceof RubyFixnum) {             return addFixnum(context, (RubyFixnum)other);         }         return addOther(context, other);     } Friday, November 4, 2011
  • 55.     private IRubyObject addFixnum(ThreadContext context, RubyFixnum other) {         long otherValue = other.value;         long result = value + otherValue;         if (additionOverflowed(value, otherValue, result)) {             return addAsBignum(context, other);         }         return newFixnum(context.getRuntime(), result);     } Friday, November 4, 2011
  • 56. Compiler • AST-walking • ASM bytecode library • Minimal optimizations • Invokedynamic really helps • IR offers new opportunities Friday, November 4, 2011
  • 57. jruby --bytecode -e “1 + 1” Friday, November 4, 2011
  • 58. ALOAD 0 INVOKEVIRTUAL ruby/__dash_e__.getCallSite0 ALOAD 1 ALOAD 2 ALOAD 1 GETFIELD org/jruby/runtime/ThreadContext.runtime INVOKESTATIC org/jruby/RubyFixnum.one LDC 1 INVOKEVIRTUAL org/jruby/runtime/CallSite.call ARETURN Friday, November 4, 2011
  • 59. public class ASTCompiler {     private boolean isAtRoot = true;     public void compileBody(Node node, BodyCompiler context, boolean expr) {         Node oldBodyNode = currentBodyNode;         currentBodyNode = node;         compile(node, context, expr);         currentBodyNode = oldBodyNode;     }          public void compile(Node node, BodyCompiler context, boolean expr) {         if (node == null) {             if (expr) context.loadNil();             return;         }         switch (node.getNodeType()) {             case ALIASNODE:                 compileAlias((AliasNode) node, context, expr);                 break;             case ANDNODE:                 compileAnd(node, context, expr);                 break; Friday, November 4, 2011
  • 60.     public void compileIf(Node node, BodyCompiler context, final boolean expr) {         final IfNode ifNode = (IfNode) node;         // optimizations if we know ahead of time it will always be true or false         Node actualCondition = ifNode.getCondition();         while (actualCondition instanceof NewlineNode) {             actualCondition = ((NewlineNode)actualCondition).getNextNode();         }         if (actualCondition.getNodeType().alwaysTrue()) {             // compile condition as non-expr and just compile "then" body             compile(actualCondition, context, false);             compile(ifNode.getThenBody(), context, expr);         } else if (actualCondition.getNodeType().alwaysFalse()) {             // always false or nil             compile(ifNode.getElseBody(), context, expr);         } else { Friday, November 4, 2011
  • 61.             BranchCallback trueCallback = new BranchCallback() {                 public void branch(BodyCompiler context) {                     if (ifNode.getThenBody() != null) {                         compile(ifNode.getThenBody(), context, expr);                     } else {                         if (expr) context.loadNil();                     }                 }             };             BranchCallback falseCallback = new BranchCallback() {                 public void branch(BodyCompiler context) {                     if (ifNode.getElseBody() != null) {                         compile(ifNode.getElseBody(), context, expr);                     } else {                         if (expr) context.loadNil();                     }                 }             };                          // normal             compile(actualCondition, context, true);             context.performBooleanBranch(trueCallback, falseCallback);         } Friday, November 4, 2011
  • 62. public abstract class BaseBodyCompiler implements BodyCompiler {     protected SkinnyMethodAdapter method;     protected VariableCompiler variableCompiler;     protected InvocationCompiler invocationCompiler;     protected int argParamCount;     protected Label[] currentLoopLabels;     protected Label scopeStart = new Label();     protected Label scopeEnd = new Label();     protected Label redoJump;     protected boolean inNestedMethod = false;     private int lastLine = -1;     private int lastPositionLine = -1;     protected StaticScope scope;     protected ASTInspector inspector;     protected String methodName;     protected String rubyName;     protected StandardASMCompiler script; Friday, November 4, 2011
  • 63.     public void performBooleanBranch(BranchCallback trueBranch, BranchCallback falseBranch) {         Label afterJmp = new Label();         Label falseJmp = new Label();         // call isTrue on the result         isTrue();         method.ifeq(falseJmp); // EQ == 0 (i.e. false)         trueBranch.branch(this);         method.go_to(afterJmp);         // FIXME: optimize for cases where we have no false branch         method.label(falseJmp);         falseBranch.branch(this);         method.label(afterJmp);     } Friday, November 4, 2011
  • 64. More Demos! • JRuby + JVM flags • JRuby concurrency • Invokedynamic (Java 7) • Redcar Editor • Ruboto (Android) • VisualVM Friday, November 4, 2011