 Components of the Stacked Architecture
========================================


CompiledFile        -- Largely ignorable

executor        # Typedef for a function pointer
Executable      # Has an executor called "execute", i.e. polymorphism by function pointer
CompiledMethod  < Executable  # By default CompiledMethod::default_executor
VMMethod
NativeMethod
NativeFunction

Runner          # Typedef for the interpreter/machine that executes the code

(There are various argument count specialization handlers for VMMethod.)

Message
SendSite
Selector

CallFrame
NativeMethodFrame
NativeMethodFraming

Task
Thread (vm/util/)
Thread (builtin)
NativeThread
ThreadState

VariableScope
StaticScope     # Lexical scope?

VM
VMManager
SharedState
Environment

Marshaller
UnMarshaller

MachineMethod
JIT
Assembler

(Locks)


 Execution Flow in the Stacked Architecture
============================================

 Flow from Startup through First Method
----------------------------------------

Environment::boot_vm()
  -> VM::boot()

Environment::signal_thread()
  -> SignalThread -> SharedState::set_signal_thread()

Environment::run_file(loader)  # kernel/loader.rb
  -> CompiledFile::load()
    -> CompiledFile()

  -> VM::thread_state()
    -> ThreadState::clear_exception()

  -> CompiledFile::execute()
    -> ->

  -> /* Check exceptions */

  -> /* Delete CompiledFile */


CompiledFile::execute()
  -> CompiledFile::body()
    -> UnMarshaller::unmarshal()  # Gives a CompiledMethod
    -> Wrap it in a TypedRoot for GC

  -> CallFrame()  # Sets up and clears fully a local CallFrame object

  -> GlobalLock::LockGuard()      # RAII global lock VM::global_lock()

  -> Message()    # Sets up message in context of "main", module Object

  -> CompiledMethod::scope()
    -> StaticScope::create()
    -> StaticScope::module()  # Set up as Object

  -> CompiledMethod::execute()
    -> ->

  -> return true

CF::execute() -> CM::execute() ~> CM::default_executor() ~> VMMethod::execute() ~> VMMethod::execute_specialized<>()

CompiledMethod::execute() == By default this is CompiledMethod::default_executor()
-> CompiledMethod::default_executor()
  -> CompiledMethod::formalize()
    -> Make the backend method, "vmm", either VMMethod()
       or PrimitiveResolver if name matches a primitive.
      -> VMMethod()
        -> Set CompiledMethod's executor to VMMethod::execute
        -> Set up literals, stack, SendSites etc.


  CompiledMethod::execute()   # Now the new backend, using VMMethod here
  ==
  VMMethod::execute()         # And vmm is the VMMethod. This actually calls:
  ==
  VMMethod::execute_specialized<GenericArguments>   # I.e., default argument handling
    -> Grab pointers to CompiledMethod, and the VMMethod *instance*, CM::backend_method()
    -> Allocate VariableScope to hold method's locals
      -> VariableScope::setup()     # Blanks out the VS and preps by Qnil locals for method
    -> Allocate CallFrame
      -> CallFrame::setup(VMMethod::stack_size()) # Prepares by blanking out
      -> THEN actually set up the CallFrame with data from this and Message.

    -> WhateverArguments::call() tries to assign the arguments. ARGUMENT CHECKING HERE.
      -> If this fails, ArgumentError gets raised in state->thread_state->raise_exception

    -> return VMMethod::run_interpreter(state, vmm, cfile)
      -> ->


    # MAIN LOOP (?)
    -> VMMethod::run_interpreter(): LOOPS UNTIL AN EXCEPTION, RETURN, BREAK or EXIT OCCURS!

      -> VM::interrupts.check ?
        ?-> VM::collect_maybe(callframe)

      -> VM::check_local_interrupts() ?         # COME BACK TO THESE
        ?-> VM::process_async(callframe) ?
          !-> return NULL

      -> VMMethod::run()      # Produces return value
        -> ->
        ?-> return returnvalue

      -> VM::thread_state() == ThreadState
        |-> cException?
          CallFrame::has_unwinds_p()   # Returns NULL if no unwinds
            ?-> UnwindInfo, CallFrame::pop_unwind()
            ?-> /* Set up unwinding here */

        |-> cReturn or cBreak?
          -> Go through any ensures in CallFrame::has_unwinds_p()'s UnwindInfo
            -> Start again at new IP

          -> If no ensures, cReturn continues raising until we are returning
              to the correct place, at which point we can return the raised
              value

          -> Break is same but does not return val

        |-> cExit just returns NULL, we are exiting

        |-> Anything else fails hard



      -> VMMethod::run() == a Runner function pointer, by default VMMethod::interpreter() in vm/llvm/instructions.cpp
        -> VMMethod::interpreter() just executes the method one opcode at a time.
          ~~> vm/instructions.rb


<---- Eventually we return or raise all the way back to CompiledMethod::execute()


 Flow of a Method Call in the Program
--------------------------------------

There are a few variants, but broadly this starts with one of the
send_* instructions in vm/instructions.rb.

