Skip to content

VM: avoid heap allocation when pushing OverloadSet constants #108

@timfennis

Description

@timfennis

Background

Object::OverloadSet stores its candidates as an owned Vec<ResolvedVar>. It lives in the constant pool as Value::Object(Box<Object>). Every time the VM executes a Constant(idx) instruction for an operator, it calls value.clone(), which:

  1. Allocates a new Box<Object> on the heap
  2. Deep-clones the Vec<ResolvedVar> inside it (another heap allocation)

This happens on every arithmetic operator call — for fib.ndc that means ~4 allocations per non-leaf frame across ~318K calls.

Proposed fix

Change Object::OverloadSet(Vec<ResolvedVar>) to Object::OverloadSet(Rc<[ResolvedVar]>).

Cloning an Rc<[T]> is an atomic reference-count increment with no heap allocation. The candidates slice is immutable after construction, so shared ownership is safe.

If issue #107 (single-candidate collapse) is implemented first, this only affects the remaining multi-candidate overload sets, but it's still worth fixing independently.

Alternative

A broader fix would be to change Value::Object(Box<Object>) to Value::Object(Rc<Object>) throughout the VM. This would make all object pushes (including function values pushed by GetGlobal) allocation-free on clone. However that is a much larger refactor and may affect mutation semantics.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions