-
Notifications
You must be signed in to change notification settings - Fork 1
Description
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:
- Allocates a new
Box<Object>on the heap - 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.