1. 46
    1. 3

      Hey this is awesome! I’ll definitely download and play. You should really join the Self mailing list and let people there know.

      A couple of off the cuff questions -

      Are you doing any sort of JIT or only an interpreter at this stage? What bytecodes are you using, your own or ones from the existing Self implementations?

      Is the VM 64 bit clean? ie are object pointers 64 bits and if so, what are smallInts? Self VM of course has 31 bit smallInts (with 1 bit for tagging)

      1. 2

        Hey there, good to see you! I will join the mailing list, thank you.

        Are you doing any sort of JIT or only an interpreter at this stage?

        I’m currently focusing on a pure interpreter. I really want to eventually make a JIT incorporating the techniques used in the Self implementation paper, but that will only be after the language becomes stable and I have a good test suite which can smoke out any bugs.

        What bytecodes are you using, your own or ones from the existing Self implementations?

        No bytecodes for the time being, the VM interprets the AST. A bytecode would probably happen on a similar timeframe as the JIT above.

        Is the VM 64 bit clean? ie are object pointers 64 bits and if so, what are smallInts?

        Yep! Object pointers are 64 bits and object memory aligns itself to 8 bytes (so any object reference has 000 as its last 3 bits). I took a look at Java’s compressed OOPs, and perhaps that could be interesting, but right now I’m working towards stability instead of memory footprint and performance improvements (those are also welcome though!) I reserved the bottom two bits, so smallInts (which I call just integers) are 62 bits.

        1. 2

          A pure interpreter should be able to run faster than jitted Self on 1980s hardware :)

          I’m not sure that exposing the byte codes to the running Self code add much over exposing the AST, but I guess you will need to do one or the other to get a Self-level debugger.

          The existing Self VM is single-threaded with preemptive multitasking done in Self code (with the help of a couple of primitives). Do you have any thought on using more than one core?

          1. 1

            Yes, actually, I do! It’s going to be the next thing I will be tackling.

            The idea can be summarized as: Put mutation of the global tree (anything reachable from lobby) under a lock, and have actors who communicate by message passing only (no shared state). Then, use a non-preemptive scheduler (closer to an event loop) which would run these actors that would pass messages to each other.

            No shared state allows me to run these actors across multiple cores with no locks, since globally reachable objects are locked (you would be able to unlock it with a special primitive that stops the world while you add stuff to the global tree, for example). Reading from the global tree would be completely lockless since you’re not mutating anything. I’d still have to figure out a way to have the message queues for each actor be lockless somehow (not sure if it’s possible, but I’ll look into it).

            I got inspired by Erlang’s actors which use message passing for concurrency, and thought it would be a great fit for the natural message passing-based style of Self.

            1. 3

              You might be interested in the Verona runtime (MIT licensed) for this. The Verona model is a generalisation over the actor model, where each cown (concurrent owner) is the root of a tree of regions and work can be scheduled to run with exclusive access to multiple cowns. Scheduling a behaviour to run over a single cown is the equivalent of sending a message to an actor (the runtime refers to scheduling a behaviour over multiple cowns as a ‘multimessage’ because it’s effectively sending a message that’s simultaneously received by multiple actors. The simultaneity makes it safe to mutate all of the actors while the message is being processed).

              You could implement your proposed model very easily on top of the Verona runtime by making the global world a cown and each actor a cown. When you wanted to access global objects, you would send a multimessage to the receiving actor and the global world. In the message handler it would then be safe to mutate both local and global objects.

              1. 1

                Ah, that’s quite interesting. That means I could treat the global tree as the same as an actor’s own object tree, if I’m understanding you correctly. Thanks for sharing this.

                1. 3

                  Yes, exactly. It requires something with the multimessage abstraction - if you don’t want to use the Verona runtime then you could probably implement it yourself (though do read the code carefully to make sure you’re getting the deadlock-freedom guarantees). Exposing a Verona-like when clause in Self would be fairly easy, I think, you just need to make sure that you have a dynamic check to enforce the region invariants that Verona enforces statically (specifically, that an object in one region doesn’t contain pointers to another region). I know this is possible because I was doing it in Smalltalk 15 years ago. Verona is what happens when you start with Actor Smalltalk but want C++ performance.