æè¡éšã®ç¬¹ç°ã§ãããã«ã¿ã€ã 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
ãšããããã©ã¡ãŒã¿åãååŸå·ãã¡ãœãããå©çšãããšã
defhello(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 ã§æžããããéãããšããããŸããå žåçãªäŸã¯ãããŒã¯ãŒãåŒæ°ã®åŠçã§ãã
# Rubydefdummy_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 Rubydefem_dummy_func_rescuenilrescuenilend
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.rbclassStringdeflength __ATTR__.pure __C__.str_length endend
# 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.rbclassStringdeflength __C__.str_length endend
ããããããã°ã©ã ã¯ã
== disasm: #<ISeq:length@string.rb:10> 0000 invokecfunc 0002 leave
ãããªæãã§ã³ã³ãã€ã«ãããŸãã
ãã ãinvokecfunc
ãçšããé¢æ°åŒã³åºãã¯ãåŸæ¥ã® C ã¡ãœããããããªãŒããããããããŸãã
- (1) åŒæ°ã VM ã¹ã¿ãã¯ã« push ããã®ã§é ã
- (2) leave åœä»€ã§ãã¬ãŒã ãæããã®ã§ã1åœä»€å®è¡ãäœåã«ãããé ã
ããã§ã(1) ã®åé¡ã®ããã«ã__C__.func(a, b)
ã«æž¡ãå®åŒæ°ãããã®ã¡ãœããã®ä»®åŒæ° def foo(a, b)
ãšãŸã£ããçãããšããVM ã¹ã¿ãã¯ã«ããã·ã¥ããã®ã§ã¯ãªããé¢æ°ã®åŒæ°ã«ã¡ãœããã®åŒæ°ããã®ãŸãŸå©çšãã invokecfuncwparam
åœä»€ãè¿œå ããããšã«ããŸããã
defdummy_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
åœä»€ã®ã¿å®è¡ããã¡ãœããã«ãªããŸãã
è©äŸ¡
ããŠãçµæã¯ã©ããªã£ãã§ããããã
defdummy_func0 __C__.dummy_func0 enddefdummy_func1 a __C__.dummy_func1(a) enddefdummy_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 codedefopen_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 == -1yield fd ensureraise'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# loadRubyVM::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 ã§ãäŒãã§ããããšã楜ãã¿ã«ããŠãããŸãã