Skip to content

Runtime

Daniel Wirtz edited this page Apr 8, 2019 · 27 revisions

NOTE: This is a work in progress and the respective PR has not yet been merged into master.


AssemblyScript provides a set of runtime templates to automatically include support for managed objects when compiling a program. As the name says, a runtime template provides functionality that performs certain operations, that cannot be performed at compile time, during runtime, like, for example:

  • Include a memory allocator to be able to use new expressions / instantiate managed classes
  • Include a garbage collector that either traces or counts the references of unreachable objects

Previous versions of the compiler didn't include any runtime functionality by default, leaving it up to the developer to import relevant implementations manually, while newer versions of the compiler include a default runtime suitable for most tasks. The runtime template to include can be specified with the --runtime flag:

  • --runtime default
    The runtime that is included by default, consisting of the TLSF memory allocator and the ITCM garbage collector.

  • --runtime arena
    A very small prototyping runtime without free/GC support.

  • --runtime none
    Just basic runtime functionality like instanceof. Equivalent to the initial bare-bones behaviour but now also including a runtime header on managed objects.

The --runtime option can also be used to specify an additional entry file relative to baseDir that sets up custom runtime functionality, i.e. picks another memory allocator or garbage collector, provides additional global functions, you name it.

Runtime functions

Depending on which runtime is used, all or part of the following interface is exposed externally. The reason for having these functions in the first place is that managed objects must be set up to function properly, like taking care of the runtime header and the ins and outs of garbage collection.

  • $.newObject(payloadSize: u32, id: u32): usize
    Allocates and registers, but doesn't initialize the data of, a new managed object of the specified kind.

    Note: If the object to be created contains reference type fields, using this API isn't sufficient because just storing their references into memory does not guarantee proper linking (your program will most likely explode). Instead, where that's the case, either export the class so its constructor can be used properly or a helper function that calls the constructor for you.

  • $.newString(length: i32): usize
    Allocates and registers, but doesn't initialize the data of, a new String of the specified length.

  • $.newArrayBuffer(byteLength: i32): usize
    Allocates and registers, but doesn't initialize the data of, a new ArrayBuffer of the specified byteLength.

  • $.newArray(id: u32, buffer: usize = 0): usize
    Allocates and registers a new Array of the specified kind using the given backing buffer.

  • $.instanceof(ref: usize, id: u32): bool
    Determines whether a managed object is considered to be an instance of the class represented by the specified runtime id.

  • $.retain(ref: usize): void
    Retains a managed object externally, making sure that it doesn't become collected.

  • $.release(ref: usize): void
    Releases a managed object externally, allowing it to become collected.

  • $.collect(): void
    Performs a full garbage collection cycle.

  • $.setArgc(argc: i32): void
    Sets the number of present arguments of the next varargs call. The loader does this automatically.

Runtime header

In order to provide the functionality mentioned above, each managed object (not annotated @unmanaged) has a hidden header that contains the necessary information. Usually, one doesn't come into contact with the runtime header because it is "hidden", that means that it is located before the address that a reference points at. However, if you are for some reason thinking of interfering with the runtime header directly, here's it's structure:

╒════════════════════ Managed header (32-bit) ══════════════════╕
   3                   2                   1
 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0  bits
├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤
│   .classId         unique id of the respective class          │
├───────────────────────────────────────────────────────────────┤
│   .payloadLength   size of 'payload'                          │
├───────────────────────────────────────────────────────────────┤
│   .reserved1       reserved space for GC                      │ ◄─┐
├───────────────────────────────────────────────────────────────┤  usize
│   .reserved2       reserved space for GC                      │ ◄─┘
╞═══════════════════════════════════════════════════════════════╡ ◄─ reference points here
│                       ... payload ...                         |

Note that messing with the runtime header directly requires deep knowledge of the ins and outs of AssemblyScript's runtime, like how it interferes with the memory manager and garbage collector interfaces and so on.

 

Clone this wiki locally