370 likes | 588 Views
Самсонов Иван, Оверсан-Скалакси. Rubinius: Ruby, написанный на Ruby. Летом 2006 года, где-то в США. А не написать ли мне свой Ruby с блекджеком и шлюхами?. Что такое Rubinius?. JIT. VM. Evan Phoenix. Ruby. Bytecode. Engine Yard. LLVM. Melbourne. Rubinius это:.
E N D
Самсонов Иван, Оверсан-Скалакси Rubinius: Ruby, написанный на Ruby
Летом 2006 года, где-то в США А не написать ли мне свой Ruby с блекджеком и шлюхами?
Что такое Rubinius? JIT VM Evan Phoenix Ruby Bytecode Engine Yard LLVM Melbourne
Rubinius это: Программа, которая транслирует код программы на Ruby, например: puts 123 в эффективный машинный код с последующим его исполнением: push %rbp; mov %rsp, %rbp; push %rbx; subq $0x98, %rsp; cmp $0x0, 0x10(%rcx); call 0xffffffffff472010; jmp 0x9c;
Rubinius это: Имплементация языка программирования Ruby
Нормально ли, что Rubinius написан на Ruby? • Да! Ведь, например: • изрядная часть языка Java написана на нём самом; • Где не получается использовать Ruby, используется C++;
Нормально ли, что Rubinius написан на Ruby? static VALUE rb_ary_collect(ary) VALUE ary; { long i; VALUE collect; if (!rb_block_given_p()) { return rb_ary_new4(RARRAY(ary)->len, RARRAY(ary)->ptr); } collect = rb_ary_new2(RARRAY(ary)->len); for (i = 0; i < RARRAY(ary)->len; i++) { rb_ary_push(collect, rb_yield(RARRAY(ary)->ptr[i])); } return collect; }
Нормально ли, что Rubinius написан на Ruby? module Enumerable defcollect ifblock_given? ary = [] each { |o| ary <<yield(o) } ary else to_a end end alias_method :map, :collect end
Потому, что Ruby: • Динамичный; • Человечный; • Удобный.
Одна из целей проекта Rubinius - сделать Ruby быстрым
История Rubinius Повторный запуск Rails Старт проекта Команда расширяется JIT VM на C++ Engine Yard нанимает Эвана Запуск Rails stackfull бренч мержится в master
Преимущества Rubinius • Компактное быстрое ядро VM; • сборщик мусора, основанный на поколениях; • поддержка расширений языка C; • большая часть кода реализована на Ruby; • JIT; • RubySpec;
Сборщик мусора • Перемещающая стратегия; • Immix mark-region сборщик;
Стадии компилятора байткода .rb файл sexps bytecode Node дерево AST
Результат компилятора байткода def foo(a,b) a + b end 0000: push_local 0 # a 0002: push_local 1 # b 0004: meta_send_op_plus :+ 0006: ret
Стадии JIT bytecode машинный код LLVM IR
Входящий Ruby-код для JIT class Flower defbloom(*a) a end end
JIT – результат преобразования 0x2280010 sub $0xc, %esp 0x2280013 mov 0x1c(%esp), %eax 0x2280017 mov %eax, 0x4(%esp) 0x228001b mov 0x10(%esp), %eax 0x228001f mov %eax, (%esp) 0x2280022 mov $0x0, 0x8(%esp) 0x228002a call 0xfffffffffde9d640 ; 0x11d650 rbx_construct_splat 0x228002f add $0xc, %esp 0x2280032 ret
Дальнейшая оптимизация: Method Inlining
Примитивы class Fixnum : public Integer { public: // Ruby.primitive! :fixnum_or Integer* bit_or(STATE, Fixnum* other); }; class Fixnum < Integer def|(o) Ruby.primitive :fixnum_or end end
Backtrace puts "123"+ 1 ruby z.rb z.rb:1:in `+': can't convert Fixnum into String (TypeError) from z.rb:1 bin/rbx z.rb Coercion error: 1.to_str => String failed (TypeError) Backtrace: Type.coerce_to at kernel/common/type.rb:22 Kernel(String)#StringValue at kernel/common/kernel.rb:112 String#+ at kernel/common/string.rb:78 main.__script__ at z.rb:1 Rubinius::CodeLoader#load_script at kernel/delta/codeloader.rb:65 Rubinius::CodeLoader.load_script at kernel/delta/codeloader.rb:88 Rubinius::Loader#script at kernel/loader.rb:435 Rubinius::Loader#main at kernel/loader.rb:526 Rubinius::Loader.main at kernel/loader.rb:552 Object#__script__ at kernel/loader.rb:564
Плагины компилятора # -*- array_zen -*- q =+[ x**2 , x.in([1,2,3])] p q # => [1, 4, 9]
Тестирование языка программирования • Mspec • RubySpec describe "Array#shift"do it "removes and returns the first element"do a = [5, 1, 1, 5, 4] a.shift.should == 5 end it "returns nil when the array is empty"do [].shift.should ==nil end end
Проблемы с Rubinius: • Отсутствие поддержки Windows; • Небольшое сообщество; • Непригоден для продакшена; • Несовместимость с некоторыми гемами (C, Ruby); • Отсутствие актуальной документации;
Пример «багов»: x = 0 loopdo puts x > -123 # => true end
Планы по развитию: • JIT • Debugger • 1.9 • Windows
Бенчмарки rubinius 1.0.0 (1.8.7 e6c32afd 2010-05-14 JI) ruby 1.9.2dev (2010-04-14 trunk 27342) ruby 1.8.7 (2010-01-10 patchlevel 249) jruby 1.6.0.dev (ruby 1.8.7 patchlevel 249) (2010-04-14 7cb1298) MacRuby version 0.6 (ruby 1.9.0)
Рекурсия deffib(n) if (n < 2) n else fib(n-1) + fib(n-2) end end
Хеш функция deffoo hash = {} 100.times {|i| hash[i] = 0} end
Простое Rails приложение • Rails 2.3.5 • WEBrick • ab -c 5 -n 1000 http://127.0.0.1:3000/ • authlogick example