mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-07-30 21:52:18 +00:00
Initial new rt integration
This commit is contained in:
@@ -8,29 +8,68 @@ It is based on [the TLSF memory manager](./tlsf.ts) and [a pure reference counti
|
||||
Interface
|
||||
---------
|
||||
|
||||
* **__rt_allocate**(size: `usize`, id: `u32` = 0): `usize`<br />
|
||||
* **__alloc**(size: `usize`, id: `u32` = 0): `usize`<br />
|
||||
Dynamically allocates a chunk of memory of at least the specified size and returns its address.
|
||||
Alignment is guaranteed to be 16 bytes to fit up to v128 values naturally.
|
||||
|
||||
* **__rt_reallocate**(ref: `usize`, size: `usize`): `usize`<br />
|
||||
* **__realloc**(ref: `usize`, size: `usize`): `usize`<br />
|
||||
Dynamically changes the size of a chunk of memory, possibly moving it to a new address.
|
||||
|
||||
* **__rt_free**(ref: `usize`): `void`<br />
|
||||
* **__free**(ref: `usize`): `void`<br />
|
||||
Frees a dynamically allocated chunk of memory by its address.
|
||||
|
||||
* **__rt_retain**(ref: `usize`): `void`<br />
|
||||
Retains a reference.
|
||||
* **__retain**(ref: `usize`): `void`<br />
|
||||
Retains a reference to an instance of a reference type. The instance doesn't become collected as long as there's at least one retained reference.
|
||||
|
||||
* **__rt_release**(ref: `usize`): `void`<br />
|
||||
Releases a reference.
|
||||
* **__release**(ref: `usize`): `void`<br />
|
||||
Releases a reference to an instance of a reference type. The instance is considered for collection once all references to it have been released.
|
||||
|
||||
* **__rt_collect**(): `void`<br />
|
||||
Forces a full garbage collection cycle.
|
||||
* **__collect**(): `void`<br />
|
||||
Forces a full garbage collection cycle. By default this means that reference cycles are resolved and possibly collected.
|
||||
|
||||
* **__rt_typeinfo**(id: `u32`): `void`<br />
|
||||
Obtains the runtime type information for objects of the kind represented by the specified id.
|
||||
* **__visit**(ref: `usize`, cookie: `u32`): `void`<br />
|
||||
Concrete visitor implementation called during traversal. Cookie can be used to indicate one of multiple operations.
|
||||
|
||||
Built-ins
|
||||
---------
|
||||
|
||||
The following functions are generated by the compiler based on compile-time information that wouldn't be available or inefficient to provide otherwise.
|
||||
|
||||
* **__info**(id: `u32`): `void`<br />
|
||||
Obtains the runtime type information for objects with the specified runtime id. Runtime type information is a set of flags indicating whether a reference type is managed, an array or similar, and what the relevant alignments when creating an instance are etc.
|
||||
|
||||
* **__visit_globals**(cookie: `u32`)<br />
|
||||
Calls `__visit` on each global that is of a reference type. Not used anymore (originally provided to support tracing GCs) but still here for possible future use.
|
||||
|
||||
* **__visit_members**(ref: `usize`, cookie: `u32`)<br />
|
||||
Calls `__visit` on each member of the instance pointed to by `ref` that is of a reference type.
|
||||
|
||||
Stub
|
||||
----
|
||||
|
||||
The fully functional yet minimal [stub implementation](./stub.ts) provides dynamic memory allocation only but doesn't include sophisticated support to deallocate objects. Useful for prototyping or very short-lived programs with hardly any memory footprint.
|
||||
A fully functional yet minimal (as in code size) [stub implementation](./index-stub.ts) that provides dynamic memory allocation but no deallocation. Useful for prototyping or very short-lived programs with hardly any memory footprint. The [none implementation](./index-none.ts) is the same as the stub implementation without any runtime exports.
|
||||
|
||||
Integration notes
|
||||
-----------------
|
||||
|
||||
Working with the runtime internals within standard library code can be tricky and requires knowledge of where the compiler will insert runtime calls automatically. For example, whenever a value of a reference type is assigned to a local, a global or a field, the compiler *might* insert a `__retain` call, respectively whenever such a value becomes unassigned from one, *might* insert a `__release` call. When a value is handled as an `usize` (i.e. when it comes from `__alloc` or is `changetype<usize>`ed), no such insertion happens (afterwards), but as soon as a `changetype<RefType>`ed (again), the side-effects introduced by automatic insertion must be understood.
|
||||
|
||||
A `__retain` call is inserted when a value of a reference type
|
||||
* is assigned to a local, global or a field **if** the value is not already the exact same value as stored before
|
||||
* is an argument to a function call, including `this` (i.e. `str.indexOf` retains `str`)
|
||||
* is returned from a function (i.e. no need to manually `__retain` if explicitly `changetype`d)
|
||||
|
||||
A `__release` call is inserted when a value of a reference type
|
||||
* becomes unassigned from a local, global or a field due to assigning a new value **if** the value is not already the exact same value as stored before
|
||||
* is popped together with its local from the current scope, i.e. a local declared with `let` in a block, or otherwise at the end of a function
|
||||
|
||||
If not taken into account properly
|
||||
* a memory leak will occur when `__retain`ed more often than intended
|
||||
* a double-free will occur when `__release`d more often than intended
|
||||
|
||||
Also note that a `load<T>(x)` with a reference type acts like a `changetype<T>(load<usize>(x))` and does not `__retain` unless the result is assigned to a local.
|
||||
|
||||
Some best practices are:
|
||||
* Use the fresh `__alloc`ed reference in `usize` form where possible, e.g. when just copying raw bytes is necessary, and `changetype` it once on return.
|
||||
* When providing such a `usize` reference to a function, if the value isn't needed anymore afterwards, just `changetype` it on the call which will `__retain` and `__release` it automatically, including freeing it if wasn't retained before, or, if still needed afterwards, assign the `changetype`d reference to a local first and provide the local as the argument, hence keeping the reference alive as long as the local or any subsequent target is.
|
||||
* If it's not avoidable to `changetype` to the actual reference type, do it inline in an expression and avoid assigning to a local.
|
||||
|
Reference in New Issue
Block a user