æè¡é¨ã®ç¬¹ç°ã§ãããã«ã¿ã¤ã Ruby ã³ããã¿ã¨ãã¦åãã¦ããã®ã§ãææ¥ããå§ã¾ã RubyKaigi 2019 ã¯ä»äºã§è¡ãã¾ãããã¾ãæ¥ã®ããããã¨ãå°ãªãæã ã®æ´ãã®èå°ã§ãã
宣ä¼ãããã¦ãRubyKaigi ä¸ã«èªåãã©ããªä»äºãããã並ã¹ã¦ã¿ã¾ããï¼ã¯ãã¯ãããå ¨è¬ã®è©±ã¯ããã¯ãã¯ãããä¸åã¯ãRubyKaigi 2019ã§ã¿ãªããã«ãä¼ãã§ãããã¨ã楽ãã¿ã«ãã¦ãã¾ãï¼ã ãã覧ä¸ããï¼ã
- æ¯æãã¯ãã¯ããããã¼ã¹ã§ãCookpad Daily Ruby Puzzlesããç´ã§é ä»ãã¾ãã®ã§ãèå³ãããæ¹ã¯ãæã¡ä¸ããã
- 1æ¥ç®
- 11:20-ãRuby 3 Progress Reportãã¾ã¤ãã¨ããã® keynote å¾ãRuby 3 ã®é²æã¿ãããªãã¨ããç´¹ä»ãã¾ãã
- 14:20-ãWrite a Ruby interpreter in Ruby for Ruby 3ãç§ã® accept ãããçºè¡¨ã§ãã
- 15:00- ä¼æ©æéãã¯ãã¯ãããã®ãã¼ã¹ã«ããã¾ãã®ã§ãã質åãããæ¹ã¯ãéã³ããã ããã°å¹¸ãã§ãã
- 3æ¥ç®
- 10:00- ãRuby Committers vs the Worldãæä¾ã®ã³ããã¿ãå£ä¸ã«ä¸¦ã¹ãåºãç©ã§ããQ&A ã«ãªããã¨æãã¾ããhttps://forms.gle/f7zZt1pKCA5HTABe9 ãããã¾ã¤ãã¨ãããã³ããã¿ã«è³ªåããå¯ãä¸ããã
- 15:00- ä¼æ©æéãã¯ãã¯ãããã®ãã¼ã¹ã«ã¦ããCookpad Daily Ruby Puzzlesãã®è§£èª¬ãé è¤ããããããã®ãçºããäºå®ã§ãã
- çµäºå¾ãRubyKaigi åä¾ä¼ã¨ãããåä¾é£ããéã¾ãå®´ä¼ãä¼ç»ãã¦ãã¾ãï¼ä¿è·è ä¼ã ã£ããããããªãï¼ã
ããæå¤ã¨å°ãªãã京é½ã§ãã£ãã¨ãã¯ãä¸æ¥ä¸ä¸¦ååã®è°è«ããã¦ããæ°ããããéå¬ã®åæ¥ã« Developer's meeting ã¨ãç¿æ¥ã« after hackathon ãããã®ã§ãã¾ããã¯ã大å¤ããç¥ãã¾ããã
ãã¦ãæ¬ç¨¿ã§ã¯ãç§ã®çºè¡¨ããWrite a Ruby interpreter in Ruby for Ruby 3ãã«ã¤ãã¦ãç´¹ä»ãã¾ããä¸æãªè±èªã§çºè¡¨ããäºå®ãªã®ã§ããã¡ãã§ã¯æ¥æ¬èªã§è¨äºã¨ãã¦æ®ãã¨ããã¨ããæå³ã«ãªã£ã¦ãã¾ãã
ãã®çºè¡¨ã¯ï¼
çºè¡¨ã¿ã¤ãã«ãç´è¨³ããã¨ããRuby 3 ã«ããã¦ãRuby ã§ã¤ã³ã¿ããªã¿ãæ¸ãã¦ãããããã¨ããæãã«ãªãã§ããããã
ä»ãMRI (Matz Ruby Interpreter) ã¯ãã»ã¼ãã¹ã¦ C ã§æ¸ããã¦ãã¾ããã¿ã¤ãã«ãèªãã¨ãããã Ruby ã«å ¨é¨ç½®ãæããããã¨è¦ããããç¥ãã¾ããããæå³ã¨ãã¦ã¯ããRuby ã§æ¸ããæ¹ãããã¨ãã㯠Ruby ã§æ¸ããããã«ããããã¨ãããã®ã§ããRuby 㧠Ruby ããã¹ã¦ self-host ããããã¿ãã㪠Rubyã§ã¤ããRuby ã®ãããªè©±ã§ã¯ããã¾ããã
ç¾å®çã«ãè¯ãæãã®ä»çµã¿ãå°å ¥ãã¦ãRuby 3 ããããããã¾ããããã¨ããææ¡ã«ãªãã¾ãã
çºè¡¨è³æ㯠http://www.atdot.net/~ko1/activities/2019_rubykaigi2019.pdf ãããã¦ã³ãã¼ãé ãã¾ãï¼ä¿®æ£çãéææ´æ°ãå ¥ãã¾ãï¼ã
èæ¯ï¼ç¾ç¶ã¨åé¡ç¹
MRI ã§ã®çµè¾¼ã¯ã©ã¹ã»ã¡ã½ããã®å®ç¾©ã®æ¹æ³
ç¾å¨ãRuby ã®çµè¾¼ã¯ã©ã¹ã»ã¡ã½ããã®ã»ã¨ãã©ã¯ãC ã§è¨è¿°ããã¦ãã¾ããString ã ã¨ãããªæãã
void Init_String(void) { rb_cString = rb_define_class("String", rb_cObject); ... rb_define_method(rb_cString, "<=>", rb_str_cmp_m, 1); rb_define_method(rb_cString, "==", rb_str_equal, 1); rb_define_method(rb_cString, "===", rb_str_equal, 1); rb_define_method(rb_cString, "eql?", rb_str_eql, 1); ... rb_define_method(rb_cString, "length", rb_str_length, 0); rb_define_method(rb_cString, "size", rb_str_length, 0); ... }
åºæ¬çã«ãrb_define_class
ã¨ããã¯ã©ã¹ã§ã¯ã©ã¹ãå®ç¾©ãã¦ããã®ã¯ã©ã¹ã« rb_define_method
ã§ã¡ã½ããã追å ãã¦ãããã¨ãããã®ã§ããrb_define_method
ã§ã¯ãååã¨å®è£
ãã¦ããé¢æ°ããããã arity ï¼å¼æ°ã®æ°ï¼ãæå®ãã¾ããString#length
ã®å ´åã¯ãrb_str_length
ã¨ããé¢æ°ã§å®è£
ããã¦ããããã§ãã
VALUE rb_str_length(VALUE str) { return LONG2NUM(str_strlen(str, NULL)); }
ãããªæãã§ãC 㧠Ruby ã®ã¡ã½ãããè¨è¿°ã§ãã¾ãããã®å ´åãString#length
ã¡ã½ãããå¼ã°ããã¨ãæçµçã«ã¯ rb_str_length()
ãå¼ã°ãããã¨ãããã®ã§ããC ããã°ã©ããªããè¦ãã°ããããããªæ§é ã«ãªã£ã¦ãã¦ãããããããã§ãã
ï¼å®ã¯ãprelude.rb
ã¨ãããRuby ã§å®ç¾©ãæ¸ãæ¹æ³ããã£ãããã¾ããããã¾ã使ããã¦ãã¾ããï¼
ãªãããã®ããã« C ã§å®ç¾©ãããã¡ã½ããã C ã¡ã½ãããRuby ã§å®ç¾©ãããã¡ã½ããã Ruby ã¡ã½ããã¨å¼ã¶ãã¨ã«ãã¾ãããã
ç¾ç¶ã®åé¡ç¹
ãã¦ããã®ããããããæ§é ã§ãããç¾å¨ã¯ããã¤ãåé¡ãããã¾ãã4ã¤ã«ã¾ã¨ãã¦ã¿ã¾ããã
- (1) ã¢ããã¼ã·ã§ã³ï¼ã¡ã¿ãã¼ã¿ï¼ã®åé¡
- (2) æ§è½ã®åé¡
- (3) çç£æ§ã®åé¡
- (4) API ã« context ã追å ãããåé¡
ãããã®åé¡ã解説ãã¾ãã
(1) ã¢ããã¼ã·ã§ã³ï¼ã¡ã¿ãã¼ã¿ï¼ã®åé¡
C ã¡ã½ããã«ã¯ãããã¤ãã®æå³ã§æ å ±ã足ãã¦ãã¾ããã
(a) Ruby ã¡ã½ããã«æ¯ã¹ã¦æ å ±ã足ãã¾ããã
ä¾ãã°ãMethod#parameters
ã¨ããããã©ã¡ã¼ã¿åãåå¾å·ãã¡ã½ãããå©ç¨ããã¨ã
def hello(msg) puts "Hello #{msg}"; end p method(:hello).parameters #=> [[:req, :msg]]
ãã®ããã«ãRuby ã¡ã½ããã®å¼æ°ã®åå msg
ãåå¾ãããã¨ãã§ãã¾ããä»ã«ããããã¯ãã¬ã¼ã¹æ
å ±ãªã©ããããªæã㧠Ruby ã¡ã½ããã«æ¯ã¹ã¦æ
å ±ãè½ã¡ã¦ããã¨ãããããã¾ãï¼æã
èããstack-prof 㧠C ã¡ã½ãããåºã¦ããªãã¦å°ããã¨ããã®ã¯ããããçç±ã§ãï¼ã
ãããã¯ãRuby ã§å®ç¾©ããã°ãæã£ã¦ããã¯ãã®æ å ±ã«ãªãã¾ãã
(b) æé©åã®ããã«å¿ è¦ãªæ å ±ã足ãã¾ããã
ã¨ãã«ãã¡ã½ãããã¾ããæé©åãè¡ããã¨ããã¨ãããã¡ã½ãããã©ã®ãããªæ§è³ªãæã¤ããä¾ãã°ãå¯ä½ç¨ãæã¤ã»æããªããã¨ããæ å ±ã¯ã¨ã¦ãéè¦ã«ãªãã¾ããããããC ã§å®è£ ãããã¡ã½ããã®æ§è³ªã調ã¹ããã¨ããã°ãC ã®ã½ã¼ã¹ã³ã¼ãã®è§£æãå¿ è¦ã«ãªããç¾å®çã§ã¯ããã¾ããã
ãã¨ã°ãstr.gsub("goodby", "hello")
ã¨ããããã°ã©ã ã§ã¯ gsub
ã«æ¸¡ããå¼æ°ãå¼ãããç¥ããªãã®ã§ãå¼ã³åºã度ã«2ã¤ã®æååãçæãã¾ããããããgsub
ã¯å¼æ°ãå¼ããªãã®ã§ãæ¬æ¥ã§ããã°ãfrozen ãªæååãï¼æ¯åçæããã«ï¼æ¸¡ãã ãã§è¯ãã¯ãã§ããfrozen-string-literal
pragma ã使ãã°ãããã°ã©ãããã®ããã«æå®ãããã¨ãã§ãã¾ãããç
©éã§ããgsub
ããã®ãããªã¡ã½ããã§ãããã¨ããæ
å ±ãä»å ã§ããã°ãMRI ãèªåçã«å¤æã§ãããã§ãï¼ããã°ãã°ï¼ã
ãããã¯ãMRI éçºè ãããã°ã£ã¦ä»ãã¦ããæ å ±ã«ãªãã¾ãã
(c) ã©ããããã¡ã½ãããå®ç¾©ãããããäºåã«ãããã¾ããã
rb_define_method
ã§å®ç¾©ããã¨ãèµ·åãçµãããªãã¨ãããã¯ã©ã¹ã«ãã©ããããã®ã¡ã½ãããå®ç¾©ãããããããã¾ãããããã£ã¦ããã°ãå
ã«ã¡ã½ãããã¼ãã«ããã®ãµã¤ãºã§ç¢ºä¿ãããã¿ãããªãã¨ãã§ãã¾ããããç¾å¨ããããã®ãã§ãã¾ããã
å®ç¾©ãäºåã«è§£æåºæ¥ãå½¢ã§æ¸ãã¦ããã°ãå¾ãããæ å ±ã§ãã
(2) æ§è½ã®åé¡
å¤ãã®å ´é¢ã§ãC 㯠Ruby ãããéãã§ããããããªçç±ãããã¾ããï¼æè¿ããªãrubyã¯ä»ã®è¨èªã¨æ¯ã¹ã¦é ãã®ã§ããããï¼ ã¨ãã Quora ã®è³ªåã«ãããã¦ã¿ã¾ããã®ã§ãããã£ããåèã«ãã¦ä¸ããï¼ãã¾ãé©æé©æãåãã¦ãè¨èªã使ãã¹ãã§ããããRuby ã®ä¸»è¦é¨åã C ã§æ¸ãã®ã¯ããããã妥å½ã ã¨æãã¾ãï¼ç¾ä»£ã§ã¯ãRust ãªã©ã®ããå®å ¨ãªè¨èªãè¦éã«ãããã¹ãã ã¨ã¯æãã¾ãï¼ã
ã§ãããããã¤ãã®å ´é¢ã§ãå®ã¯ Ruby 㯠C ã§æ¸ããããéããã¨ãããã¾ããå ¸åçãªä¾ã¯ããã¼ã¯ã¼ãå¼æ°ã®å¦çã§ãã
# Ruby def dummy_func_kw(k1: 1, k2: 2) dummy_func2(k1, k2) end
ããããå¦çã C ã§æ¸ããã¨ããã¨ãçµæ§é¢åã§ãããããªæãã«ãªãã¾ãã
static VALUE tdummy_func_kw(int argc, VALUE *argv, VALUE self) { VALUE h; ID ids[2] = {rb_intern("k1"), rb_intern("k2")}; VALUE vals[2]; rb_scan_args(argc, argv, "0:", &h); rb_get_kwargs(h, ids, 0, 2, vals); return tdummy_func2(self, vals[0] == Qundef ? INT2FIX(1) : vals[0], vals[1] == Qundef ? INT2FIX(2) : vals[1]); }
ãããã®ã¡ã½ããã®é度ãæ¯è¼ãã¦ã¿ã¾ãããã
ãã¼ã¯ã¼ãå¼æ°ããªãã¨ãã¯ãC ã®æ¹ãéãã§ããã¨ããã®ããRuby ã§ã® dummy_func2()
å¼ã³åºãã¯ãC ã§ã® tdummy_func2)()
é¢æ°å¼ã³åºããããå§åçã«é
ãããã§ãã
ãããããã¼ã¯ã¼ããä¸ããã¨ãå§åçã« Ruby ã§æ¸ããæ¹ãéãã§ããã¨ããã®ãããã¼ã¯ã¼ãå¼æ°ã®ããã¡ã½ããã«ãRuby ã§ãã¼ã¯ã¼ãå¼æ°ã渡ãã¨ãã¯ãããã·ã¥ãªãã¸ã§ã¯ããçæããªããç¹å¥ãªæé©åãæ½ããã¦ããããã§ãã
ä¾å¤å¦çããåããããªçç±ã§ Ruby ã§æ¸ããæ¹ãéãã§ãã
# in Ruby def em_dummy_func_rescue nil rescue nil end
static VALUE dummy_body(VALUE self) { return Qnil; } static VALUE dummy_rescue(VALUE self) { return Qnil; } static VALUE tdummy_func_rescue(VALUE self) { return rb_rescue(dummy_body, self, ãããããããããããã dummy_rescue, self); }
ãã®ããã«ããã¾ã«ãããRuby ã§æ¸ããæ¹ãããå ´åããC ã§æ¸ãã¡ãããã¨ããåé¡ãããã¾ãã
(3) çç£æ§ã®åé¡
(2) ã§ä¾ãåºããããã«ãRuby ã ã¨æ°è¡ã®ãã®ããC ã§æ¸ãã¨ä½åè¡ãè¤æ°é¢æ°ã«ã¾ããããã¿ãããªãã¨ãããèµ·ãã¾ãã C ã§è¡¨ç¾ããããã«ãããããªãé¨åãªãã§ããã大å¤ã§ãã
ä¾å¤å¦çãã¤ãã¬ã¼ã¿ããã¼ã¯ã¼ãå¼æ°ã®å¦çãªããã該å½ãããã§ãã
ã¾ãããã¾ãå¼ã°ããªãã¡ã½ããã®å ´åãããã£ã¨ Ruby ã§å®ç¾©ãã¡ãã£ã¦ãããããããã¾ããããä»ã 㨠gem ã§ããã£ã¦è¨ãããããããã¾ããã...ã
ä½è«ã§ãããç§ã¯ C ã§ãã¼ã¯ã¼ãå¼æ°ã®å¦çãæ¸ããããªãéãã¦ãprelude.rb
㧠Ruby 2.6 ã§å°å
¥ãã TracePoint#enable(target:)
ãå®è£
ãã¾ããã楽ã ã£ãã¼ã
(4) API ã« context ã追å ãããåé¡
rb_deifne_method()
ã§ç»é²ããé¢æ°ã®å¼æ°ã¯ãåºæ¬çã« self
ã¨ãã©ã¡ã¼ã¿æ
å ±ã«ãªãã¾ããããããæã
ãé²ãã¦ãã並åå¦çæ©æ§ã§ãã Guild ã§ã¯ãç¾å¨ã®ãã³ã³ããã¹ããæ
å ±ã渡ãå¿
è¦ãããã¾ããmruby ã«ããã mrb_state *
ã§ãã
# mruby String#length static mrb_value mrb_str_size(mrb_state *mrb, mrb_value self) { mrb_int len = RSTRING_CHAR_LEN(self); return mrb_fixnum_value(len); }
Thread-local-storage (TLS) ã«ä¿åãããã¨è¨ãæ¹æ³ãããã¾ãããã¨ãã« shared library çµç±ã§å©ç¨ããã¨ãã¨ã¦ãé ããã¨ãç¥ããã¦ãã¾ãï¼è©³ç´°ã¯ã笹ç°ç:Ruby ç¨ãã«ãä»®æ³ãã·ã³ã«ãã並åå¦çã®å®ç¾ (2012)ï¼ãããã§ã第ä¸å¼æ°ã«ãmruby ã¿ããã«æ å ±ãå¼ã渡ãããããã« API ã®å¤æ´ãå¿ è¦ã§ãã
åé¡ã®æå¾ (4) ã«æã£ã¦ãã¾ããããå人çã«ã¯ãããä¸çªãªãã¨ããããåé¡ã§ãããã åã« API ãå¤æ´ãã¦ãããªããªã追å¾ãã¦ããããªããã§ãããããããªç¹å ¸ãã¤ããã»ãã移è¡ãããããããã¨ããæ¦ç¥ã§ãã
åé¡ã®ã¾ã¨ã
4ã¤ã®åé¡ãã¾ã¨ãã¾ããã
- (1) ã¢ããã¼ã·ã§ã³ï¼ã¡ã¿ãã¼ã¿ï¼ã®åé¡ã-> DSL ãå¿ è¦
- (2) æ§è½ã®åé¡ -> æã Ruby ã®ã»ããéã
- (3) çç£æ§ã®åé¡ -> Ruby ã§ååã®ã¨ãããã
- (4) API ã« context ã追å ãããåé¡
(1) ã¯ãæ°ãã«ã¡ã½ããå®ç¾©ã®ããã® DSL ãããã°è§£æ±ºãããã§ãããããããããã°ãDSL ãæ§ç¯ããããè¨èªã«å¿å½ããããã£ããããªï¼
解決æ¡ï¼Ruby ãã¤ãããï¼
åé¡ã解決ããããã«ãRuby ã§å®ç¾©ãããã¯å®£è¨ãè¡ããã¨ãèãã¾ããããã¹ã¦ã Ruby ã§ç½®ãæããããã§ã¯ãªããC ã§æ¸ããæ¹ãããã¨ãã㯠C ã§æ¸ãã¦ãRuby ã®å®ç¾©ããç°¡åã«å¼ã³åºããããã«ããã°ï¼FFIã®å°å ¥ï¼ãæ¢åã®è³ç£ãæå¹æ´»ç¨ã§ããC ã®å§åçãªæ§è½ãå©ç¨ã§ãã¦è¯ãããã§ãã
Ruby ã§æ¸ãã¦ããã°ãå¾ãã解æãããã¨ã§ããããããªãã¨ããããã¾ããã¾ããå é¨DSLçã«ã¡ã½ããã«ã¢ããã¼ã·ã§ã³ãä»ãããã¨ãå¯è½ã§ãããã
åé¡ç¹ã¯ãã®ããã«è§£æ±ºã§ãã¾ãã
- (1) ã¢ããã¼ã·ã§ã³ï¼ã¡ã¿ãã¼ã¿ï¼ã®åé¡ã-> Ruby 㧠DSL ãæ¸ãã¦è§£æ±º
- (2) æ§è½ã®åé¡ -> ç´ ç´ã« Ruby ãå¾æãªã¨ãã㧠Ruby ãæ¸ãã°è§£æ±º
- (3) çç£æ§ã®åé¡ -> Ruby ã§ç°¡åã«æ¸ãã¨ãã㯠Ruby ã§æ¸ã¾ããã¨ã§è§£æ±º
- (4) API ã« context ã追å ãããåé¡ -> FFI 㧠context ã渡ãããã«ããã°è§£æ±º
æ°ããæ¸ãæ¹
ã§ã¯ãå ·ä½çã«ã©ããªãµãã«æ¸ãã¦ããã§ããããã
æååã®ã¡ã½ãããå®ç¾©ãã string.rb
ãæ°è¨ããlength
ã¡ã½ãããå®ç¾©ãããã¨ãèãã¾ãã
# string.rb class String def length __ATTR__.pure __C__.str_length end end
# String#length impl. with new FFI static VALUE str_length(rb_ec_t *ec, VALUE str) { return LONG2NUM( str_strlen(str, NULL)); }
ãããªæãã§ã__C__.str_length
ã¨æ¸ãã¨ãstr_length()
ãå¼ã°ãããã¨ããä»çµã¿ã§ãã
ãªãã__C__
ã¯é©å½ã§ããå¤åãå¤ããã¨æãã¾ããã¾ããç¹å¥ãªå®è¡ã¢ã¼ãã§ã®ã¿å©ç¨å¯è½ã«ãªãã¨æãã¾ããæ®æ®µã¯ãã¼ã«ã«å¤æ°ï¼ãããã¯ã¡ã½ããåï¼ã§ããã
__ATTR__.pure
ãé©å½ã«ã§ã£ã¡ããã¦ãã ãã§ããããããªæãã§ãString#length
ã®å±æ§ã人éãæ¸ããããã«ãã¦ãããã°ãªã¨æã£ã¦ãã¾ãã
ããã使ãã¨ãããã°ã©ãã¯ãããªæãã«ãªãã¨æãã¾ãã
- Ruby ã®æ©è½ã使ããã¨ã§ãç°¡åã«æ¸ããã¨ããã¯ç°¡åã«æ¸ããããã«ãªãã
- C ã®é¢æ°ãç°¡åã«å¼ã¹ãã®ã§ãæ§è½ãè½ã¨ããã«ã¡ããã¨æ¸ããããã«ãªãã
- ããã¤ãã®ç¹ã«æ°ãä»ããªããã°ãªããªã
- GVL ãªãªã¼ã¹ããGC ã¿ã¤ãã³ã°ãªã©ãå¤ããã®ã§ãæ°ã«ãã人ã¯ãã«ããªãã¨ããã¾ããã
- å¾æ¥éãã«ããããã°ãåã« C ã®é¢æ°ãå¼ã³åºããã¨ããããã«ãªãã¾ãã
çå
ãã¦ãã©ãã§ãããããæ¸ãããããè¯ããããªæããããªãã§ããããã
ãã ããã£ã¨ãããã©ã¼ãã³ã¹ã«ã¤ãã¦æ°ã«ãã人ï¼ç§ã¨ãï¼ã¯ã次ã®ç¹ãæ°ã«ãªããªãã§ããããã
- ã©ã³ã¿ã¤ã ãªã¼ããããï¼FFI 㧠C é¢æ°å¼ã³åºãã£ã¦é ãããããªãã®ï¼
- ã¹ã¿ã¼ãã¢ããæéï¼Ruby ã¹ã¯ãªãããèªã¿è¾¼ããããã¹ã¿ã¼ãã¢ããæéãé·ããªã£ã¦ãã¾ãããããªãã®ï¼
ãã®äºã¤ã®çåã«çããããã«ãæ¬çºè¡¨ã§ã¯ã次ã®äºã¤ã®æè¡çææã«ã¤ãã¦ãç´¹ä»ãã¾ãã
- é«é㪠FFI ãå®ç¾ããããã® VM å½ä»¤ã®è¿½å
- ãã¼ãæéåæ¸ã®ããã®ã³ã³ãã¤ã«ãã¤ããªãã©ã¼ãããã®æ¹å
ãã£ããçµè«ãç³ãã¾ãã¨ããã®äºã¤ã®æè¡çææãç¨ãããã¨ã§ãC ã§å ¨é¨æ¸ãããã¯ãè¥å¹²é ããã©ãã§ãååéããªãã®ã§ãå¤ååé¡ãªãããããªãããªï¼ãã¨ããæãã§ãã
ããã¾ã§ãã¦ããã£ã¨æ¬é¡ã«ãã©ãçãã¾ããã
é«é㪠FFI ãå®ç¾ããããã® VM å½ä»¤ã®è¿½å
é·ããªã£ãã®ã§ãæçã«è¡ãã¾ãã
__C__.func(a, b)
ã®ããã«é¢æ°ãå¼ã³åºããããã«ããããã«ãinvokecfunc
ã¨ããå½ä»¤ã VM ã«è¿½å ãã¾ãããfiddle ãªã©ã®ããã«ã¦ã§ã¢ãç¨ããã« C ã®é¢æ°ãå¼ã³åºãã®ã§é«éã§ãã
# string.rb class String def length __C__.str_length end end
ããããããã°ã©ã ã¯ã
== disasm: #<ISeq:[email protected]:10> 0000 invokecfunc 0002 leave
ãããªæãã§ã³ã³ãã¤ã«ããã¾ãã
ãã ãinvokecfunc
ãç¨ããé¢æ°å¼ã³åºãã¯ãå¾æ¥ã® C ã¡ã½ããããããªã¼ãããããããã¾ãã
- (1) å¼æ°ã VM ã¹ã¿ãã¯ã« push ããã®ã§é ã
- (2) leave å½ä»¤ã§ãã¬ã¼ã ãæããã®ã§ã1å½ä»¤å®è¡ãä½åã«ãããé ã
ããã§ã(1) ã®åé¡ã®ããã«ã__C__.func(a, b)
ã«æ¸¡ãå®å¼æ°ãããã®ã¡ã½ããã®ä»®å¼æ° def foo(a, b)
ã¨ã¾ã£ããçããã¨ããVM ã¹ã¿ãã¯ã«ããã·ã¥ããã®ã§ã¯ãªããé¢æ°ã®å¼æ°ã«ã¡ã½ããã®å¼æ°ããã®ã¾ã¾å©ç¨ãã invokecfuncwparam
å½ä»¤ã追å ãããã¨ã«ãã¾ããã
def dummy_func2 a, b __C__.dummy_func2(a, b) end
0000 invokecfuncwparam<dummy_func2/2> 0002 leave
ããã§ãã(1) å¼æ°ã VM ã¹ã¿ãã¯ã« push ããã®ã§é ããã®åé¡ã解決ãã¾ããçµã¿è¾¼ã¿é¢æ°ã¯ãã ããã C ã§æ¸ãã¦ããé¢æ°ããã®ã¾ã¾å¼ã¶ãã¨ã«ãªãããããªããã¨æãã®ã§ï¼ã¤ã¾ããC é¢æ°ã¸ã® delegator ã®ãããªå®è£ ã«ãªãããããªããã¨æãã®ã§ï¼ããã®å½ä»¤ãä½ã価å¤ã¯ããã®ã§ã¯ãªããã¨å¤æãã¾ããã
ããã¦ãleave
ããããã次å½ä»¤ã§ããã®ã¯ç¡é§ãããªããã¨è¨ããã¨ã§ãinvokecfuncwparam
å½ä»¤ã®æ¬¡ã®å½ä»¤ã leave
ã®å ´åããã®å½ä»¤å
ã§ãã¬ã¼ã ãçµäºããã invokecfuncwparamandleave
å½ä»¤ãç¨æãã¾ããã
ã¤ã¾ããä¸è¨ dummy_func2
é¢æ°ã¯ã次ã®ããã«ã³ã³ãã¤ã«ããã¾ãã
0000 invokecfuncwparamandleave ⦠0002 leave
TracePoint
ã® return
ã¤ãã³ãã«å¯¾å¿ããããã«ãleave
ã¤ãã³ãã¯æ®ãå¿
è¦ãããã¾ãããåºæ¬çã«ã¯ invokecfuncwparamandleave
å½ä»¤ã®ã¿å®è¡ããã¡ã½ããã«ãªãã¾ãã
è©ä¾¡
ãã¦ãçµæã¯ã©ããªã£ãã§ããããã
def dummy_func0 __C__.dummy_func0 end def dummy_func1 a __C__.dummy_func1(a) end def dummy_func2 a, b __C__.dummy_func2(a, b) end
ãã®ããã«å®ç¾©ããã¡ã½ããã¨ãããã«å¯¾å¿ãã C ã¡ã½ããã®å®è£ ã®å®è¡æéãæ¯ã¹ã¦ã¿ãã®ã次ã®ã°ã©ãã§ãã
invokecfunc
ãç¨ããã®ã¿ã baseline ã§ãããããã 㨠C ã¡ã½ãããããé
ãã£ãã®ããæé©åãçµã¿åããããã¨ã§ãCã¡ã½ãããããé«éã«å®è¡ã§ãããã¨ããããã¾ãã
çºè¡¨è³æã«ã¯ãããå°ããããããªè©ä¾¡ãããã®ã§ããã¡ãããåç §ä¸ããã
ã¾ã¨ãã¨ä»å¾ã®èª²é¡
ã¾ã¨ããã¨ããFFI ãç¨ããã¨ãã©ã³ã¿ã¤ã ãªã¼ããããã¯é«ãã®ã§ã¯ï¼ãã¨ããç念ã«å¯¾ããããªãã§ãããå¼·ãæ°æã¡ããã£ã¦æé©åãè¡ãã¨ãåé¡ãªãï¼ãã¨ãå¤ãï¼ããã¨ãããã¨ã§ããæ§è½ãæ°ã«ãããRuby ã§æ¸ãããã§ãã
ä»å¾ã®èª²é¡ã¨ãã¦ããªãã·ã§ãã«å¼æ°ãªã©ã¯ã¾ã é ãã®ã§ããªã¼ãã¼ãã¼ãã£ã³ã°ã®ä»çµã¿ãå ¥ãããªã©ãã¦ãå ¸åçãªä¾ã¯éããã¿ãããªãã¨ãç®æããã°ã¨æã£ã¦ãã¾ããå¼æ°ã®æ°ã«ãã£ã¦ã¡ã½ããå®è£ ãé¸ã¶ãããªãã¨ãæ³å®ãã¦ãã¾ãããã¤ã³ã©ã¤ã³ãã£ãã·ã¥ã使ããã®ã§ããããã feasible ãªã®ã§ã¯ãªããã¨æã£ã¦ãã¾ãã
é¢é£ç 究ã«ãç§ã10å¹´åã«ãã£ã¦ãããRicsin: Rubyã«Cãåãè¾¼ãã·ã¹ãã (2009.3)ãã¨ããç 究ãããã¾ããããã¯ãRuby ã®ä¸ã«ãç´æ¥ C ã®ããã°ã©ã çãåãè¾¼ããããã«ãããã¨ããç 究ã§ãã
# Writing C in Ruby code def open_fd(path) fd = __C__(%q{ // passing string literals to __C__ methods /* C implementation */ return INT2FIX(open(RSTRING_PTR(path), O_RDONLY)); }) raise 'open error' if fd == -1 yield fd ensure raise 'close error' if -1 == __C__(%q{ /* C implmentation */ return INT2FIX(close(FIX2INT(fd))); }) end
C ã®ä¸ãããRuby ã®å¤æ°ã«ã¢ã¯ã»ã¹ã§ããã®ããã¢é¢ç½ãã¨ããã ã¨æã£ã¦ãã¾ããå°æ¥çã«ã¯ãããããæ¡å¼µãã§ããããã«ãã¦ãé¢ç½ãããç¥ããªãã¨æã£ã¦ãã¾ãã
ãªããæ¬ç¨¿ã§ã¯ãFFI ã®å®è£ ã«å¿ è¦ã«ãªãé¢æ°ãã¼ãã«ã®ä½æé¨åã¯ãã¡ãã£ã¨é¢åãªã®ã§çç¥ãã¾ãããæ£ç´ãããããã¼ãã¹ãã©ããã§ä¸çªé£ããã¨ãããªãã§ãããã
ãã¼ãæéåæ¸ã®ããã®ã³ã³ãã¤ã«ãã¤ããªãã©ã¼ãããã®æ¹å
ã©ã³ã¿ã¤ã ãªã¼ããããã®æ¸å¿µã解æ¶ããããã次ã¯ã¹ã¿ã¼ãã¢ããã¿ã¤ã ã伸ã³ã¦ãã¾ãããããªããã¨ããæ¸å¿µã«ã¤ãã¦ã®è¿çã§ããRuby ã§ã¡ã½ãããå®ç¾©ããããã«ããããè¤æ°ã® .rb ãã¡ã¤ã«ãèµ·åæã«èªãããé ãããªããããªãã®ãã¨ãã話ã§ãã
Ruby ã§ã¯ 2.3 ããããã¤ãã³ã¼ãï¼MRI ã§ã¯ ISeq ã¨ããç¨èªã使ãã¾ãï¼ããã¤ããªã«ãã³ãããä»çµã¿ãæã£ã¦ãã¾ãã
# dump bin = RubyVM::InstructionSequence#to_binary # load RubyVM::InstructionSequence.load_from_binary(bin)
AOT ã³ã³ãã¤ã«ã¿ãããªç¨èªã使ã£ã¦ãããã¨æãã¾ããbootsnap ã§ã使ã£ã¦ãã¾ãããäºåã«ã³ã³ãã¤ã«ãããã¨ã§ãã³ã³ãã¤ã«ã®ã³ã¹ããæããããããããªãããã¨ããæå¾ ã§ä½ã£ããã®ã§ãã
ã§ããã®ãã¤ããªãã¼ã¿ããä¾ãã° C ã®é å表ç¾ã«ã㦠MRI ã¨ä¸ç·ã«ã³ã³ãã¤ã«ããã°ãMRI ã®ãã¤ããªã«çµ±åãããã¨ãã§ãã¾ããã¡ãªã¿ã«ãèµ·åå¾ã« mmap ãã¦ããã ãããåããããªæãã«ãããã¨ãã§ãã¾ããå®é¨ã§ã¯ãåè ã使ãã¾ããããæ£ç´æåãã mmap ã§ããã°ããã£ããªã
ã§ãããã ãã ã¨ãªããªã®ã§ãäºã¤ã®ä»çµã¿ãããã«æå¹ã«ãããã¨ã§ãããå¹ççã«åºæ¥ãããããªããã¨æãã¾ãã
Lazy ãã¼ãã£ã³ã°
ISeq ã¯ãããªã¼æ§é ã«ãªã£ã¦ãã¾ãããããã¬ãã« iseq ããã¯ã©ã¹å®ç¾© iseq ããã¡ããããã¡ã½ãã iseq ãæã¤ãã¨ããæãã§ããã¡ã½ãããèµ·åãããªãéããã¡ã½ãã iseq ã¯ä½¿ããã¾ãããã¤ã¾ããiseq ã®ãã¼ãããå®éã«ä½¿ãããã¾ã§ãé 延ãããã¨ãã§ããã¨ãããã¨ã§ããããã lazy ãã¼ãã£ã³ã°ã¨è¨ãã¾ãã
å®ã¯ããã® lazy ãã¼ãã£ã³ã°ãRuby 2.3 ã®æ®µéã§å
¥ã£ã¦ãããã§ããï¼vm_core.h ã® USE_LAZY_LOAD
ãã¯ãï¼ãã¤ãã¤ã使ããªãããªã¼ã¨æã£ã¦ããã§ãããèµ·åæã«å
¨é¨ã® iseq ãä½ãããããå®éã«ä½¿ãã¡ã½ããããããã¯ã ããã¼ãããã»ããå§åçã«éãã®ã§ããããæå¹ã«ãã¡ãããããªãã¨æã£ã¦ãã¾ãã
ããã¦ããããããã°ã©ã ã§å¼ã°ããã¡ã½ãããªãã¦ãå®ç¾©ãããã¡ã½ããã®ããä¸é¨ã§ããããããããããç´å¾æãã話ãªããããªããã¨æãã¾ãã
ãã¼ãæ¸ã¿ãã¤ãã¤ããã§ãã¯ãå ¥ãã®ã§ãè¥å¹²é ããªããã§ãããåå²äºæ¸¬ã§ååã«ãã¼åºæ¥ãç¯å²ããªãã¨æã£ã¦ãã¾ãã
ãªãããã®ä»çµã¿ã«ã¤ãã¦ã¯ãRubyKaigi 2015 ã®ç§ã®çºè¡¨ããã笹ç°ç: Rubyå¦çç³»ã®ã³ã³ãã¤ã«æ¸ã¿ã³ã¼ãã®è¨è¨ (2015)ãã«è©³ããã§ãããã3ï½4å¹´åãªãã ãªã
è¤æ°ã®ãã¡ã¤ã«ããµãã¼ã
ç¾å¨ã® compiled binary ã¯ãä¸ã¤ã®ãã¡ã¤ã«ãä¸ã¤ã®ãã¤ããªãåºãããã«ãããªã£ã¦ãã¾ãããããããè¤æ°ã®ãã¡ã¤ã«ãã¾ã¨ãã¦ä¸ã¤ã®ãã¤ããªã«ããã°ãå ±æé¨åãå¢ãã¦ããªã½ã¼ã¹ãè¥å¹²ç¯ç´ã§ãã¾ãï¼å¤åï¼ã
ããã§ãè¤æ°ãã¡ã¤ã«ãä¸ã¤ã® compiled binary ã«ã¾ã¨ãããã¨ãã§ããããã«ãã¾ãããç¾å¨ã¯æ°å¤ã¤ã³ããã¯ã¹ã§ããã¢ã¯ã»ã¹åºæ¥ã¾ãããããã¡ã¤ã«åã§ã¢ã¯ã»ã¹ã§ããããã«æ¡å¼µããäºå®ã§ãã
bin = RubyVM::InstructionSequence.to_binary(iseq1, iseq2, ...)
ã¨è¤æ°ã® iseq ãèªã¿è¾¼ã¿ã
loader = RubyVM::InstructionSequence::Loader.new(bin) iseq0 = loader.laod(0)
ã®ããã«åãåºããã¨ãã§ããããã«ãã¦ã¿ã¾ããã
è©ä¾¡
è©ä¾¡ã®ããã«ã3000åã®ã¯ã©ã¹ C0ï½C2999 ãä½ããåã¯ã©ã¹ã 1ï½20åã®ã¡ã½ãããæã¤ï¼def m0; m; end
ã®ãããªåç´ãªã¡ã½ãããå
¨åè¨3ä¸ã¡ã½ãããããï¼ãã¨ãããµã³ãã«ãä½ã£ã¦å®é¨ãã¦ã¿ã¾ããã
- 1ãã¡ã¤ã«ã«è©°ãè¾¼ãå ´å
- .rb ã 582KB
- compiled binary ã 16MB
- ããã C ã®é å表ç¾ã«ãã㨠79MBï¼ï¼ï¼
- åã¯ã©ã¹ãã¨ã«ãã¡ã¤ã«ãä½ã
- .rb ã 3000 å
- ã¾ã¨ãã compiled binary ã 17MB
- ããã C ã®é å表ç¾ã«ãã㨠86MB
- å¾æ¥ã® C ã¡ã½ããã§ã®å®ç¾©ã®ä»æ¹ãç¨ããã¨ã4.2MB ã® .c
ãã®3éããç¨ãã¦ããã¼ãã㦠Ruby ãèµ·åããæéãã¯ãã£ã¦ã¿ã¾ããããªãã--disable-gems
㧠rubygems ãªã©ã®ã©ã¤ãã©ãªã¯ãã¼ãããªãããã«ãªã£ã¦ãã¾ãã
çµæã¯æ¬¡ã®ããã«ãªãã¾ããã
çµæãè¦ãã¨ãå¾æ¥ã® C ã§ã®å®ç¾©ãæãéã 27.5 ç§ã§ãlazy loading ãç¨ãããã¨ã§ãã ããã 2 åç¨åº¦ã®æ§è½ä½ä¸ã§æ¸ããã¨ããå ·åã§ãã
åãªã compiled binary ã®ãã¼ãã 㨠3 åé ããæ®éã« .rb ã¨ãã¦ãã¼ãããããã6ï½16åç¨åº¦é ããã¨ããçµæã«ãªãã¾ããï¼ä¸çªä¸ã®çµæã²ã©ããªï¼ãã¨ããããã§ãå¾æ¥ææ³ã«æ¯ã¹ãã¨ããã¯ãéãã®ã ããã©ãã¾ã C ã¡ã½ããå®ç¾©ã«åã°ããã¨ããã¨ããã§ãã
ã¾ã¨ãã¨ä»å¾ã®èª²é¡
工夫ã«ãã£ã¦ãã¹ã¿ã¼ãã¢ããã¿ã¤ã ã«ã¤ãã¦ã¯ãå¾æ¥ã® C ã¡ã½ããã®ãã¼ãæéããå¤§å¹ ã«é ããã¨ãããã¨ã¯ãªãã£ãã®ã§ãããã¾ã è¥å¹²é ãã§ããããå°ããªãã¨ããªããªãã§ããããã
.rb ãæ¸ãã¦ããã¨ãäºåã«ã©ã®ã¯ã©ã¹ã«ã©ããªã¡ã½ãããå®ç¾©ããããã¨ããã®ããããã®ã§ãå ã«ãã¼ãã«ã ãä½ã£ã¦ããã¦ãã¡ã½ããåãåãããæ¥ãã¨ãã«åã㦠iseq ã®ãã¼ããå§ãããããªããã lazy ãªããæ¹ãªãããå¹ããããç¡ããã¨æãã¾ããããã¾ã§ããã°ãC ã¡ã½ããã®ãã¼ããããéããªãããããªãããªï¼
ãã¨ãåç´ã«ã³ã³ãã¤ã«æ¸ã¿ãã¤ããªããã£ã¡ãã§ãããã§ããããããã¨å°ããããªãããã«ãããã§ããããããã«å¤§ããããªã®ã§ãªãã¨ãããããå¤åãç°¡åã« 1/5 ãããã«ã¯ãªãã¨æãã¾ãã誰ããã£ã¦ããã¾ããï¼
æ¬ç¨¿ã®ã¾ã¨ã
æ¬ç¨¿ã§ã¯ãç§ã® RubyKaigi 2019 ã®çºè¡¨ã§ãããWrite a Ruby interpreter in Ruby for Ruby 3ãã«ã¤ãã¦è¿°ã¹ã¾ããã
ç¾å¨ MRI ã§ã¯ãã»ã¼ãã¹ã¦ C ã§è¨è¿°ããã¦ãã¾ããããããè¯ãæãã« Ruby ã¨æ··ããããã«ãç¹å¥ãª FFI è¨æ³ã®å°å ¥ãææ¡ãã¾ããã
ããã¦ãããã§æ¸å¿µããããã©ã³ã¿ã¤ã ãªã¼ãããããããã³ãã¹ã¿ã¼ãã¢ããã¿ã¤ã ã®å¢å ãã«ã¤ãã¦ãããã¤ãã®ãã¯ããã¯ããç´¹ä»ãããããã feasible ãªçµæãåºããã¨ã§ãæ¸å¿µãããããææã§ããããããªããã¨æãã¾ãã
ç¾å¨ã®çµè¾¼ã¯ã©ã¹ã»ã¡ã½ããã®å®ç¾©ãæ¸ãæããã¨ãªãã¨ãå¤ãã®äººæãå¿ è¦ã«ãªãã¾ããã¾ã ããã®æ¹é㧠Ruby 3 åãï¼Ruby 2.7 åãããªï¼ï¼ã«æ¸ãæããã¨ããåæã¯åãã¦ãã¾ããããåãããã°ã°ã°ã¼ã¨æ¸ãæããä½æ¥ãçºçãã¾ããããç¨åº¦æ©æ¢°çãªä½æ¥ã«ãªããã§ãããè¯ãæ©ä¼ãªã®ã§èå³ãããæ¹ãä¸ç·ã«ããã¾ãããï¼
ãããã㯠Ruby Hack Challengeãã¨ããã¤ãã³ããéå¬ãã¦ããã次å㯠Ruby Hack Challenge Holiday #3 ã 5/11 (å) ã«è¡ãã¾ããããããå ´ã§ãRuby (MRI) éçºã«åå ãã¦ãããæ¹ãããã£ãããã¾ããããã声ããé ãã¾ããã幸ãã§ãã
ã¨ããããã§ãRubyKaigi 2019 ã§ãä¼ãã§ãããã¨ã楽ãã¿ã«ãã¦ããã¾ãã