2019-04-04 02:25:22 +02:00
..
2019-04-02 10:12:57 +02:00
2019-03-27 14:43:35 +01:00
2019-04-02 10:12:57 +02:00
2019-04-04 02:25:22 +02:00
2019-03-26 23:35:08 +01:00
2019-04-02 10:12:57 +02:00

Garbage collector interface

A garbage collector for AssemblyScript must implement the following common and either the tracing or reference counting interfaces:

Common

  • __ref_collect(): void
    Triggers a full garbage collection cycle. Also indicates the presence of a GC.

Tracing

  • __ref_register(ref: usize): void
    Sets up a new reference.

  • __ref_link(ref: usize, parentRef: usize): void
    Links a reference to a parent that is now referencing it.

  • __ref_unlink(ref: usize, parentRef: usize): void
    Unlinks a reference from a parent that was referencing it. Implementation is optional.

  • __ref_mark(ref: usize): void
    Marks a reference as being reachable so it doesn't become sweeped.

Reference counting

  • __ref_register(ref: usize): void
    Sets up a new reference. Implementation is optional.

  • __ref_retain(ref: usize): void
    Retains a reference, usually incrementing RC.

  • __ref_release(ref: usize): void
    Releases a reference, usually decrementing RC.

Typical patterns

Standard library components make use of the interface where managed references are stored or deleted. Common patterns are:

General

/// <reference path="./collector/index.d.ts" />

if (isManaged<T>()) {
  // compiled only if T is a managed reference
  ... pattern ...
}

Insertion

if (isNullable<T>()) {
  if (ref) {
    if (isDefined(__ref_link)) __ref_link(ref, parentRef);
    else if (isDefined(__ref_retain)) __ref_retain(ref);
    else assert(false);
  }
} else {
  if (isDefined(__ref_link)) __ref_link(ref, parentRef);
  else if (isDefined(__ref_retain)) __ref_retain(ref);
  else assert(false);
}

Replacement

if (ref !== oldRef) {
  if (isNullable<T>()) {
    if (isDefined(__ref_link)) {
      if (isDefined(__ref_unlink)) if (oldRef) __ref_unlink(oldRef, parentRef);
      if (ref) __ref_link(ref, parentRef);
    } else if (isDefined(__ref_retain)) {
      if (oldRef) __ref_release(oldRef);
      if (ref) __ref_retain(ref);
    } else assert(false);
  } else {
    if (isDefined(__ref_link)) {
      if (isDefined(__ref_unlink)) if (oldRef) __ref_unlink(oldRef, parentRef); // *
      __ref_link(ref, parentRef);
    } else if (isDefined(__ref_retain)) {
      if (oldRef) __ref_release(oldRef); // *
      __ref_retain(ref);
    } else assert(false);
  }
}

Deletion

if (isNullable<T>()) {
  if (ref) {
    if (isDefined(__ref_link)) {
      if (isDefined(__ref_unlink)) __ref_unlink(ref, parentRef);
    } else if (isDefined(__ref_retain)) __ref_release(ref);
    else assert(false);
  }
} else {
  if (isDefined(__ref_link)) {
    if (isDefined(__ref_unlink)) __ref_unlink(ref, parentRef);
  } else if (isDefined(__ref_retain)) __ref_release(ref);
  else assert(false);
}

(*) Note that some data structures may contain null values even though the value type isn't nullable. May be the case when appending a new element to an array for example.