by

Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    Brian Shirai
    @brixen
    keep this in mind, too, a CompiledCode object is basically a template for code execution, describing the things that are needed to run the code, but that object is input for creating a MachineCode instance, and that has the actual instruction function pointers in the opcodes vector, and then the CallFrame instance is created per invocation
    Laurent Julliard
    @ljulliar
    Ok so the size of the stk is actually (sizeof(Object) (stack_size)
    Brian Shirai
    @brixen
    so you need to understand both the CompiledCode and the MachineCode objects
    Laurent Julliard
    @ljulliar
    Yes i got that toot
    too
    CompiledCode, MachineCode, Interpreter and CallFrame seem to be the crucial bits, right ?
    Brian Shirai
    @brixen
    the stk struct element is a pointer to 1+ Object* (which is an intptr_t), so the total space that stk points to will be the stack size + the register size. You can see what were the CallFrame is allocated via that macro
    yes, those are the key data structures
    Laurent Julliard
    @ljulliar
    Ok I see that's what the prepare function shows: stack and then registers (https://github.com/rubinius/rubinius/blob/43a6850f4ef8f23c53bc804f30fa9128588bd204/machine/call_frame.hpp#L216)
    are initialized there
    Laurent Julliard
    @ljulliar
    I have a design decision to make about call frames allocation. I can either to allocate cal frmaes through the dynamic memory allocator that I have already written (in other words I allocate on the HEAP) OR I allocate them back to back on the STACK which usually in most operating system grows in the opposite direction of the HEAP. The STACK usualyy starts at the top of the memory and grows downwards. The HEAP grows from low memory address upward
    If I use the HEAP all kind of objects will be mixed together: for instance objects from the bytecode interpreter (such as callframes) and Ruby objects instantiated at runtime.
    I don't know what is best... Any advice
    Brian Shirai
    @brixen
    I’m not sure about the wasm vm, I generally know what you stated about how stack vs heap memory is managed, but does it matter? I’d suggest doing whatever is easy now unless you have a good reason for why one approach is better.
    Laurent Julliard
    @ljulliar
    @brixen :The one criterai I have in mind is: are the call frmaes always managed in a LIFO way ? As new call frame is being created each time you call a new method I guess it should be LIFO but aren't there cases where we need to keep a particular call frame because it will later be needed in a gvien execution contaxt ?
    context
    If it's not LIFO, then it's not worth bothering about the management of a separate STACK for call frames. Allocating them and chaining them on the HEAP will do.
    Chuck Remes
    @chuckremes
    why not just allocate and chain on the HEAP? it covers all of your cases
    i’m not sure how closures are implemented in rbx, but it’s likely that a callframe could be captured/retained as part of a closure, so behavior definitely won’t be LIFO in that situation
    Brian Shirai
    @brixen
    in the Rubinius vm, we promote variables to the heap when a scope may survive the lifetime of the call frame, that's implemented in the instructions, so you'll get it for free by implementing the instructions
    but "should I just chain them on the heap?" is exactly the question I'm referring to above... isn't it easier to just start with that? is there a good reason not to?
    Laurent Julliard
    @ljulliar
    The reason for not doing it was speed. malloc'ing objects is going to be way slower than managing a LIFO structure (probably an order of magnitude if not two). But I know what you are going to tell me: nothing is worse than optimizing too early...
    Laurent Julliard
    @ljulliar
    @brixen : I'm following you for CompiledCode and MachineCode, although in Wasm the difference is going to be quite minimal because the opcodes used in CompiledCode are actually used as is as function pointer in Wasm thanks to the call_indirect instruction which takes as argument an index in an array of fuctions. There might be other processing happening between CompiledCode and MachineCode that I'm not aware of though
    @brixen: can you be more specfiic about "the CallFrame instance is created per invocation?
    Per invocation of what exactly ?
    Brian Shirai
    @brixen
    per invocation of the code (method or function)
    the CallFrame is the invocation frame
    if performance is that different then that sounds like a reason to use one instead of the other
    Laurent Julliard
    @ljulliar
    Hi there. How are you all doing ? It has been a while... Working from home here but busy like never before ! It took me quit some time to release version 0.5.0 of Rlang. Remember ? The subset of Ruby that compiles directly to WebAssembly.
    I needed to have full support for instance variables, inheritance and modules and also minimal support for Arrays. So I added it to 0.5.0
    Now restarting the work on implementing Rubinius VM instructions.
    Talking about that, could use some help to help me understand the add_scope instructions aned especially this line scope->functions(state, call_frame->lexical_scope()->functions());
    Laurent Julliard
    @ljulliar
    it seems that the functions method is used twice: once with argument and a second time without arguments. I could find the definition of functions as an accessor in LexicalScope class but I couldn't find where the form with arguments is defined. Can you help ?
    Brian Shirai
    @brixen
    hey @ljulliar good to hear you're well! I understand busy, you'd think with no commute it would be possible to get more done, but then there's just more to do :laughing:
    Brian Shirai
    @brixen
    @ljulliar so, you could likely ignore that line, it's where I'm starting to add functions (actual functions)
    remember that "everything" in Ruby (not really, but it's the illusion we'll run with for now), and that constants are looked up via lexical scope, not inheritance chain
    add_scope adds a new scope to the chain
    push_scope pushes whatever the scope is onto the stack
    I'll try to illustrate it (but always check my math! :grinning: )
    Brian Shirai
    @brixen
    #class foo.rb
    
    # there's a lexical scope right here at script level
    # add_scope
    I_m_a_script_constant = 1
    
    class Foo
      # now there's a new lexical scope, which has script scope as parent
      And_I_m_a_class_constant = 2
    
      def m
        c = Rubinius::LexicalScope.of_sender
        while c
          puts "weee, I'm a #{c.inspect}"
          c = c.parent
        end
      end
    
      def n
        m
      end
    end
    
    Foo.new.n
    # Output
    #   weee, I'm a #<Rubinius::LexicalScope:0x2f0 parent=#<Rubinius::LexicalScope:0x2f8 parent=nil module=Object> module=Foo>
    #   weee, I'm a #<Rubinius::LexicalScope:0x2f8 parent=nil module=Object>
    LexicalScope used to be ConstantScope in Rubinius
    and it is distinct from VariableScope
    both are named according to what they are :grinning:
    in that example, you also see the distinction between Ruby and Rubinius, in that LexicalScope really is an object
    btw, congrats on all the progress on Rlang
    but now it makes me think of the missed opportunity to compete with Erlang by calling it Arrlang :laughing:
    Laurent Julliard
    @ljulliar
    I see exactly what you mean for LexicalScope. I had to implement that logic in Rlang 0.5.0 for constant lookup.
    And as for the name, I really wanted to call it Rlang in refernce to Slang but I know this is a difficult name :-) Basically if you type Rlang in Google, you have zero chance of finding my Rlang :-) Talk about working for the glory :-)
    Laurent Julliard
    @ljulliar
    Now that Rlang is functionally rich enough to start writing a real VM, I also needed tthe generated Web Assembly code to interact with the outside world. So I just put together a first version of Rlang to WASI Interface. For now it can read and write to file descriptors. See this short video showing a simple Rlang program printing command line arguments and echoing some input too.
    Brian Shirai
    @brixen
    @ljulliar sweet!