runtime-model.txt 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. // sketch
  2. struct proc {
  3. word_t mem_budget;
  4. word_t tick_budget;
  5. word_t curr_mem;
  6. word_t curr_ticks;
  7. stk_seg *stk;
  8. byte_t *env; // optional -- closures only
  9. msg_que *q;
  10. regs saved_regs;
  11. void state[]; // computed
  12. }
  13. struct regs {
  14. word_t pc;
  15. word_t sp;
  16. word_t gprs[n];
  17. }
  18. struct stk_seg {
  19. stk_seg *prev;
  20. stk_seg *next;
  21. word_t size;
  22. word_t live;
  23. byte_t frames[]; // computed
  24. }
  25. struct frame {
  26. frame_desc *desc; // points to the code + frame descriptor
  27. void *retpc;
  28. void *yieldpc; // optional
  29. byte_t *env; // optional -- closures only
  30. byte_t slots[]; // computed
  31. }
  32. struct vec {
  33. word_t refs;
  34. word_t size;
  35. word_t live;
  36. word_t init;
  37. byte_t slots[]; // computed
  38. }
  39. Stack segments are arranged in a linked list off a proc. The first is
  40. small-ish, and each subsequent segment in the list is double the size
  41. of the previous. probably there are only a few. It is important not to
  42. waste too much time shuffling or reallocating stack segments, else you
  43. lose the benefit!
  44. returning from a frame when live = 0 means going back to
  45. prev. entering a frame when live + framesz > size means allocating a
  46. next and going to it.
  47. Ok. So if this is the "rough" shape of the runtime model, how do we
  48. implement it? To interface with system libraries we really have no
  49. choice -- especially on win32 -- but to go through their shared libs.
  50. So we interface with them at a loader level. We have a bunch of
  51. addresses of entries into their system. We still have the problem of
  52. implementing the basic rust runtime services -- processes, schedulers,
  53. allocation, CoW, generic traversal, loading and unloading, signals,
  54. i/o multiplexing -- which are "under" the rust language semantics.
  55. The answer is perhaps surprising. We implement a librustrt.so /
  56. rustrt.dll in C. This contains the runtime system needed by rust
  57. crates; it's the part that converts rust's abstractions to OS
  58. abstractions. Rust *crates* are executable ELF or PE files that import
  59. the rust rt library and contain a tiny executable entry stub that
  60. simply pushes the address of the rust entry point -- different from
  61. the process entry point! -- for the crate on the C stack and calls
  62. into the rt library. The rt library initializes itself, sets up
  63. function pointers in an interface table, pushes a pointer to that
  64. table on the stack and calls *back* through the provided pointer into
  65. the crate, to the provided rust entry point. Rust then saves registers
  66. and commences normal operation, with the provision that it now has a
  67. special pointer into the rt service table that it can call through to
  68. get common things done.
  69. But there is a twist: rust crates can *also* be LoadLibrary()'ed or
  70. dlopen()'d and have the "rust entry point" extracted *by a host
  71. process*; the rust entry point is the sole exported OS-visible symbol
  72. in a rust crate. So if that host process provides a suitable function
  73. pointer table then the rust crate can be run as an embedded
  74. component. Turns out you can dynamically link a ".EXE" file or an ELF
  75. executable just fine.
  76. The key point is that rust crates are activated explicitly and
  77. parameterized explicitly by an interface table *passed into them* at
  78. runtime. They do not use indirect jumps through the PE import table or
  79. ELF PLT. So the dynamic linking is something you get to do manually,
  80. or let the startup stub code in the executable do it, in which case it
  81. uses its sole imported symbol -- the rust runtime library import entry
  82. -- to set up a standard interface and use it.
  83. Smashing!