///|
fn Store::trace_native_continuation(
  self : Store,
  handle : Int64,
  pending : Array[@types.Value],
  trace : GcTrace,
) -> Unit {
  let reference = (handle << 1) | 1L
  if !trace.native_continuations.contains(reference) {
    trace.native_continuations.set(reference, true)
    for word in self.native_execution.continuations().gc_roots(reference) {
      if word < 0L && (word & 1L) != 0L {
        pending.push(ContRef(word >> 1))
      } else if @native_bridge.is_exception_ref(word) {
        trace.push_native_root(self.decode_native_exception(word), pending) catch {
          _ => trace.failed = true
        }
      } else if @native_bridge.decode_gc_heap_ref(word) is Some(child) {
        pending.push(
          if self.references.native.c_heap is Some(heap) && heap.is_array(child) {
            ArrayRef(child)
          } else {
            StructRef(child)
          },
        )
      }
    }
  }
}

///|
fn Store::trace_object_fields(
  self : Store,
  index : Int32,
  pending : Array[@types.Value],
  trace : GcTrace,
) -> Unit {
  match self.references.native.c_heap {
    None =>
      try {
        match self.heap.get(index) {
          Struct(object) =>
            for field in object.fields {
              pending.push(field)
            }
          Array(object) =>
            for element in object.elements {
              pending.push(element)
            }
        }
      } catch {
        _ => trace.failed = true
      }
    Some(heap) => {
      let local_type = heap.get_type_idx(index)
      match self.gc_type_definition(index, local_type) {
        Some({ composite: Struct(definition), .. }) =>
          for field, definition in definition.fields {
            if definition.storage_type is Val(ty) && gc_reference_type(ty) {
              trace.push_native_root(self.struct_get(index, field), pending) catch {
                _ => trace.failed = true
              }
            }
          }
        Some({ composite: Array(definition), .. }) =>
          if definition.element.storage_type is Val(ty) && gc_reference_type(ty) {
            for element in 0.. trace.failed = true
              }
            }
          }
        _ =>
          // Untyped low-level allocations keep the conservative raw-word
          // contract. Validated module objects use their declared fields.
          for word in heap.reference_candidates(index) {
            if word < 0L && (word & 1L) != 0L {
              pending.push(ContRef(word >> 1))
            } else if @native_bridge.is_exception_ref(word) {
              trace.push_native_root(
                self.decode_native_exception(word),
                pending,
              ) catch {
                _ => trace.failed = true
              }
            } else if @native_bridge.decode_gc_heap_ref(word) is Some(child) {
              pending.push(
                if heap.is_array(child) {
                  ArrayRef(child)
                } else {
                  StructRef(child)
                },
              )
            }
          }
      }
    }
  }
}

///|
fn Store::reclaim_native_continuations(self : Store) -> Unit {
  self.native_execution.continuations().reclaim_retired()
}

///|
fn Store::release_native_exception(self : Store, index : Int32) -> Unit {
  self.references.release_native_exception(index)
}

///|
fn Store::trace_table_roots(
  _self : Store,
  table : Table,
  pending : Array[@types.Value],
  trace : GcTrace,
) -> Unit {
  for index in 0.. trace.push_native_root(value, pending)
        Managed(_) => pending.push(value)
      }
    } catch {
      _ => trace.failed = true
    }
  }
}