Library Code ActiveSupport (v7) 😵 😵 😵 Before Ruby Box: Global Only Monkey patches overwrite things globally class String def +(other) = “self:#{other}” User Library Code
Process Application Code Test Case ( _test.rb) Monkey Patches Test Runner Application Code Monkey Patches Application Code Test Case ( _test.rb) Test Case ( _test.rb) Test Case ( _test.b.rb) Test Case ( _test.b.rb) “.b.rb” su ff ix is just my idea - there should be be tt er rules.
in box, then pulling public APIs from the box ˒ Packages never break other packages or libraries ˒ Many things to be solved to realize this idea ˒ ActiveSupport? Hook points? Memory usage? Packaging w/ Underlying Boxes
h tt ps://rubykaigi.org/2024/presentations/tagomoris.html ˒ Scripts(.rb) and Extensions(.so) Loading in Boxes “State of Namespace” h tt ps://rubykaigi.org/2025/presentations/tagomoris.html ˒ Current Box Management/Detection This Talk RUBY BOX INGREDIENTS class.c load.c vm.c
can de fi ne/refer classes/methods anytime ˒ Current box should be determined whenever Ruby runs (and then, classes/methods for the box will be fetched) Current Box Management/Detection
# #<Ruby::Box:3,user,optional> … b1.require_relative(“app”) … p b1::App.foo Ruby Code using Ruby Box # app.rb p 1 module App def self.foo(x=:bar) [:foo, x].map{ it.to_s } end p 2 end
˒ #require, #require_relative, #load (and #eval) ˒ The target code is required/loaded in the receiver box ˒ Box boundary is fi le, but fi le doesn’t determine its box ˒ A fi le can be loaded in 2 boxes Current Box: Dynamic File Scope?
b1 = Ruby::Box.new … b1.require_relative(“app”) … p b1::App.foo Evaluated immediately De fi nition created De fi nition created Evaluated when called # app.rb p 1 module App def self.foo(x=:bar) [:foo, x].map{ it.to_s } end p 2 end
'Ruby::Box#require_relative' from main.rb:5:in '<main>' Where is it now? (Using Exception) # app.rb p 1 module App def self.foo(x=:bar) [:foo, x].map{ it.to_s } end raise “yay” end
control frames ˒ Hide C-level informations (show them just like Ruby-level one) ˒ Hide internal frames (DUMMY, IFUNC, etc) Backtrace and Control Frames
b = 1 def self.foo(x=:bar) c = 1 [:foo, x].map{ it.to_s } end p b end p a # main.rb w/ RUBY_BOX=1 …… b1 = Ruby::Box.new … b1.require_relative(“app”) … p b1::App.foo
def self.foo(x=:bar) c = 1 [:foo, x].map{ it.to_s } end p b end p a # main.rb w/ RUBY_BOX=1 …… b1 = Ruby::Box.new … b1.require_relative(“app”) … p b1::App.foo main Finding Current Box
def self.foo(x=:bar) c = 1 [:foo, x].map{ it.to_s } end p b end p a # main.rb w/ RUBY_BOX=1 …… b1 = Ruby::Box.new … b1.require_relative(“app”) … p b1::App.foo main Finding Current Box
def self.foo(x=:bar) c = 1 [:foo, x].map{ it.to_s } end p b end p a # main.rb w/ RUBY_BOX=1 …… b1 = Ruby::Box.new … b1.require_relative(“app”) … p b1::App.foo b1 Finding Current Box
def self.foo(x=:bar) c = 1 [:foo, x].map{ it.to_s } end p b end p a # main.rb w/ RUBY_BOX=1 …… b1 = Ruby::Box.new … b1.require_relative(“app”) … p b1::App.foo b1 Finding Current Box
def self.foo(x=:bar) c = 1 [:foo, x].map{ it.to_s } end p b end p a # main.rb w/ RUBY_BOX=1 …… b1 = Ruby::Box.new … b1.require_relative(“app”) … p b1::App.foo b1 Finding Current Box
def self.foo(x=:bar) c = 1 [:foo, x].map{ it.to_s } end p b end p a # main.rb w/ RUBY_BOX=1 …… b1 = Ruby::Box.new … b1.require_relative(“app”) … p b1::App.foo b1 Finding Current Box
def self.foo(x=:bar) c = 1 [:foo, x].map{ it.to_s } end p b end p a # main.rb w/ RUBY_BOX=1 …… b1 = Ruby::Box.new … b1.require_relative(“app”) … p b1::App.foo b1 Finding Current Box
def self.foo(x=:bar) c = 1 [:foo, x].map{ it.to_s } end p b end p a # main.rb w/ RUBY_BOX=1 …… b1 = Ruby::Box.new … b1.require_relative(“app”) … p b1::App.foo b1 Finding Current Box
def self.foo(x=:bar) c = 1 [:foo, x].map{ it.to_s } end p b end p a # main.rb w/ RUBY_BOX=1 …… b1 = Ruby::Box.new … b1.require_relative(“app”) … p b1::App.foo main Finding Current Box
def self.foo(x=:bar) c = 1 [:foo, x].map{ it.to_s } end p b end p a # main.rb w/ RUBY_BOX=1 …… b1 = Ruby::Box.new … b1.require_relative(“app”) … p b1::App.foo b1 Finding Current Box
def self.foo(x=:bar) c = 1 [:foo, x].map{ it.to_s } end p b end p a # main.rb w/ RUBY_BOX=1 …… b1 = Ruby::Box.new … b1.require_relative(“app”) … p b1::App.foo b1 Finding Current Box
def self.foo(x=:bar) c = 1 [:foo, x].map{ it.to_s } end p b end p a # main.rb w/ RUBY_BOX=1 …… b1 = Ruby::Box.new … b1.require_relative(“app”) … p b1::App.foo b1 Finding Current Box
def self.foo(x=:bar) c = 1 [:foo, x].map{ it.to_s } end p b end p a # main.rb w/ RUBY_BOX=1 …… b1 = Ruby::Box.new … b1.require_relative(“app”) … p b1::App.foo b1 Finding Current Box
def self.foo(x=:bar) c = 1 [:foo, x].map{ it.to_s } end p b end p a # main.rb w/ RUBY_BOX=1 …… b1 = Ruby::Box.new … b1.require_relative(“app”) … p b1::App.foo main Finding Current Box
Find the closest Ruby frame ˒ If it’s running a C func, trace back to the closest Ruby frame ˒ Find the “LOCAL” variable scope from the Ruby frame ˒ Check the box of the LOCAL env
ep: env pointer Control Frame and Environment struct rb_control_frame_struct { const VALUE *pc; VALUE *sp; const rb_iseq_t *_iseq; VALUE self; const VALUE *ep; const void *block_code; void *jit_return; }; typedef struct rb_control_frame_struct rb_control_frame_t; rb_control_frame_t env VALUE LVAR … VALUE LAST_LVAR VALUE ME_CREF // ep[-2] VALUE SPECVAL // ep[-1] VALUE FLAGS // ep[0] VALUE ENV // rb_env_t*
Control Frame and Environment env VALUE d VALUE c VALUE x VALUE ME_CREF // ep[-2] VALUE SPECVAL // ep[-1] VALUE FLAGS // ep[0] VALUE ENV // rb_env_t* def self.foo(x=:bar) c = 1 [:foo, x].map{ it.to_s } d = 2 end
METHOD, BLOCK, CLASS, TOP, CFUNC, IFUNC, EVAL, RESCUE, DUMMY ˒ F: Frame Flags (8bits) FINISH, CFRAME, LAMBDA, … ˒ E: Env Flags (4bits) LOCAL, ESCAPED, WB_REQUIRED, ISOLATED ˒ X: Tag for GC marking (to mimic Fixnum) Frame/Env Flags struct rb_control_frame_struct { // …… const VALUE *ep; // …… }; ————————————————————- VALUE ME_CREF // ep[-2] VALUE SPECVAL // ep[-1] VALUE FLAGS // ep[0] M M M M M M M M M M M M M M M M _ _ _ F F F F F F F F E E E E X
fi nition, called_id, owner ˒ Method De fi nition (mdef) (rb_method_definition_struct) can have box (rb_box_t *box) ˒ BH: Block Handler ˒ CREF: Class REFerence fl ags, re fi nements, klass_of_self, next, scope_visibility ˒ Prev EP: Previous Env Pointer ENV Values a = 1 PROC1 = ->(){ a * 2 } module App def self.foo c = 2 [:foo, :bar].map{ s = it.to_s ->(){ s * c } } end end env1 env2 env3 env4 env5 env6
fi nition, called_id, owner ˒ Method De fi nition (mdef) (rb_method_definition_struct) can have box (rb_box_t *box) ˒ BH: Block Handler ˒ CREF: Class REFerence fl ags, re fi nements, klass_of_self, next, scope_visibility ˒ Prev EP: Previous Env Pointer ENV Values a = 1 PROC1 = ->(){ a * 2 } module App def self.foo c = 2 [:foo, :bar].map{ s = it.to_s ->(){ s * c } } end end env1 env2 env3 env4 env5 env6
fi nition, called_id, owner ˒ Method De fi nition (mdef) (rb_method_definition_struct) can have box (rb_box_t *box) ˒ BH: Block Handler ˒ CREF: Class REFerence fl ags, re fi nements, klass_of_self, next, scope_visibility ˒ Prev EP: Previous Env Pointer ENV Values a = 1 PROC1 = ->(){ a * 2 } module App def self.foo c = 2 [:foo, :bar].map{ s = it.to_s ->(){ s * c } } end end env1 env2 env3 env4 env5 env6
fi nition, called_id, owner ˒ Method De fi nition (mdef) (rb_method_definition_struct) can have box (rb_box_t *box) ˒ BH: Block Handler ˒ CREF: Class REFerence fl ags, re fi nements, klass_of_self, next, scope_visibility ˒ Prev EP: Previous Env Pointer ENV Values a = 1 PROC1 = ->(){ a * 2 } module App def self.foo c = 2 [:foo, :bar].map{ s = it.to_s ->(){ s * c } } end end env1 env2 env3 env4 env5 env6
˒ Find the closest Ruby frame ˒ If it’s running a C func, trace back to the closest Ruby frame ˒ Find the “LOCAL” variable scope from the Ruby frame ˒ Check the box of the LOCAL env ˒ SPECVAL or ME_CREF->mdef
box ˒ In Class/Top frames ˒ Class de fi nition frame can be marked with its box ˒ In Top frames ˒ How can we mark the Top frames? Bootstrapping Problem
marking TOP frame ˒ $LOAD_PATH is to resolve fi le paths BEFORE loading fi les ˒ Global variables for loading should switch the e ff ective boxes earlier than the current box (after red, before green line frame) The “Loading” Box? -- Control frame information ------------------------------------------- c:0005 p:---- s:0019 e:000018 l:y b:---- r:0x0 CFUNC :bug! c:0004 p:0003 s:0015 e:000014 l:y b:0003 r:0x0 TOP ……/app.rb:2 [FINISH] c:0003 p:---- s:0012 e:000011 l:y b:---- r:0x0 CFUNC :require_relative c:0002 p:0023 s:0007 E:000030 l:n b:---- r:0x0 EVAL ./main.rb:5 [FINISH] c:0001 p:0000 s:0003 E:000738 l:y b:---- r:0x0 DUMMY [FINISH]
with VM_FRAME_FLAG_BOX_REQUIRE ˒ Finding the loading box ˒ Find the VM_FRAME_FLAG_BOX_REQUIRE frame ˒ Fetch cfp->self to get the receiver Ruby::Box instance Or the current box on the cfp (if the self is missing) A New Frame Flag: BOX_REQUIRE
Ruby VM ˒ De fi ning things in box: Class/Method/etc de fi nitions (class.c) ˒ Loading things in box: Evaluating scripts / Loading binaries (load.c) ˒ Finding boxes: Executing Ruby programs (vm.c) ˒ Tour must be pleasure, probably……? 🤔 Tour of Ruby Box ≒ Tour of (a part of) Ruby VM
˒ loads multi AWS Lambda functions in a process ˒ separates them incompletely ˒ A blog post about its feature and my motivation ˒ h tt ps://tagomoris.hatenablog.com/entry/2022/12/15/133450 ˒ … then, I forgot the motivation ˒ “Multiverse Ruby” “Yes! I have the motivation on that problem!” “Multiverse Ruby” Shock
Day 46: The proposal #19744 “Namespace on read” ˒ Day 78: My 1st talk about this idea at MatueRubyKaigi ˒ Day 166: Ruby Association Grant selected my project ˒ 1Y1D: My talk “Namespace, What and Why” in RubyKaigi 2024 ˒ 1Y3D: Matz “Ruby 4.0 with Packaging based on Namespace” Timeline 1