This site describes solve-engine as it is on main: 2.43.0, which npm does not have yet. npm installs 2.40.0, so a page may show an answer that version does not give yet.
VMConfig
Defined in: packages/engine/src/constants/Configuration.ts:353
Virtual Machine configuration. Controls the internal bytecode VM that executes compiled expressions.
Properties
Section titled “Properties”maxAllocatedElements
Section titled “maxAllocatedElements”readonly maxAllocatedElements: number;Defined in: packages/engine/src/constants/Configuration.ts:391
Maximum elements (collection Values, matrix cells) one evaluation may materialize in total.
maxCollectionSize above bounds a single collection. This bounds the sum
of everything an expression asks for, which is a different question and
the one that actually protects the host: two collections that are
individually legal are legal together, and an operation whose result is
the PRODUCT of two legal operands is bounded by neither of them. A matrix
multiply is exactly that shape, so three lines within every other limit
(:a = map(1*x, 0:20000), :b = transpose(a), b * a) asked for four
hundred million cells and aborted the process.
Counted in elements rather than bytes, because a count is what a call site has before it allocates. An element is 8 bytes as a numeric matrix cell and closer to a hundred as a full Value, so the default is worth roughly 16 MB of matrix or 200 MB of expanded collection: far past any document and far short of what an editor cannot survive.
maxCollectionSize
Section titled “maxCollectionSize”readonly maxCollectionSize: number;Defined in: packages/engine/src/constants/Configuration.ts:371
Maximum elements a collection may be expanded to before map/reduce/
sum/prod will iterate it.
A Range is stored as its two bounds and costs nothing until something
materializes it, at which point it becomes one Value per element. Twenty
characters (sum(x, 1:100000000)) therefore asked for a hundred million
of them, and neither maxInstructions nor maxStackDepth could see it:
the expansion happens inside a single opcode, so the instruction counter
is never consulted while it runs, and the elements never reach the value
stack. V8 aborted the whole process with “Reached heap limit”, which a
host embedding the engine cannot catch.
maxFunctionCalls
Section titled “maxFunctionCalls”readonly maxFunctionCalls: number;Defined in: packages/engine/src/constants/Configuration.ts:411
Maximum user-defined-function calls one evaluation may make in TOTAL, however deeply or widely they nest.
maxFunctionRecursionDepth bounds how DEEP calls nest and cannot see
how MANY there are, and those are different numbers. Twenty-two lines of
f(n)(v) = f(n-1)(v) + f(n-1)(v) reach a depth of only 22 against a
limit of 50, and make 2,097,152 calls doing it: a fatal heap abort in
under a second. maxInstructions cannot bound it either, because
executeBytecode() re-enters itself per call and each reentrant call
gets its OWN instruction count, so recursion refreshes its allowance on
the way in. This is the tally that does not refresh; see
vm/AllocationBudget.ts, which holds it for the same reason it holds
the element tally.
Counted in calls rather than in the instructions they run, because the call is the thing that multiplies: every call allocates a frame, its arguments and its result whatever its body says.
maxGoalSeekIterations
Section titled “maxGoalSeekIterations”readonly maxGoalSeekIterations: number;Defined in: packages/engine/src/constants/Configuration.ts:426
Hard ceiling on how many bisection steps goal seek (solve line N for <var> = <target>, see packages/goalseek/) may take before it gives up
with a structured error rather than continuing.
Goal seek re-evaluates the target line’s expression once per step while
narrowing an interval, and an untrusted document must never be able to
make that loop spin. maxInstructions bounds each individual
re-evaluation, but not how many of them the search performs, so this is
the tally that bounds the search itself, the same reason maxFunctionCalls
exists alongside maxInstructions. Bisection halves the interval every
step, so a hundred steps resolves an input to roughly one part in 2^100:
far past any precision a document needs, and a definite stop either way.
maxInstructions
Section titled “maxInstructions”readonly maxInstructions: number;Defined in: packages/engine/src/constants/Configuration.ts:357
Maximum opcodes executed per expression, halts runaway infinite loops
maxLineRunsPerPass
Section titled “maxLineRunsPerPass”readonly maxLineRunsPerPass: number;Defined in: packages/engine/src/constants/Configuration.ts:450
Hard ceiling on the work one pass over a document may do across its lines, counted in line runs (#711).
Every other limit here counts work inside one expression. The forms that
reach across lines were capped one line at a time: a sweep at 100,000
line re-runs, goal seek at maxGoalSeekIterations probes, a span
aggregate (total above, a section, a tag, a table column) not at all.
Twenty sweep lines, each inside its own cap, made one parseDocument
re-run 2,000,000 lines, and a host re-parses on every keystroke.
One count per pass: a what-if or sweep charges each line it re-runs, a
goal-seek probe one, and a span aggregate the lines it reads at sixteen
to a run (see vm/PassWork.ts, which measured the rate). The line whose
work would cross this is refused with PASS_WORK_BUDGET_EXCEEDED, and
the lines above keep their answers.
A million line runs is about five seconds of work on the machine it was measured on (a re-run costs about 5.2 µs there): ten sweeps at their own cap, or a ledger with a running total after each of about 4,000 entries. A document that needs more is extreme, and the setting says how to allow it.
maxRetainedElements
Section titled “maxRetainedElements”readonly maxRetainedElements: number;Defined in: packages/engine/src/constants/Configuration.ts:471
Hard ceiling on the elements a document keeps in its lines’ answers, counted each pass (#694): a list or matrix its cells, text one element to eight characters, any other answer one.
maxAllocatedElements bounds what one evaluation may create, and
nothing bounded what a document keeps across its lines: 500 lines of
:m = map(10*x, 0:99999), 13 KB of text, kept 50,000,000 elements and
385 MB of heap, every line inside every per-line limit.
The line whose answer would take the document past this is refused with
DOCUMENT_ELEMENT_LIMIT_EXCEEDED, and a name it assigned is let go, so
the value is not kept through a variable either. The lines above keep
their answers. The count starts again on every pass, so an edited or
deleted line’s answer stops counting when it does.
Ten million is five lines at maxAllocatedElements, or a hundred
100,000-element lists: about 80 MB of plain numbers, measured at about
8 bytes an element.
maxStackDepth
Section titled “maxStackDepth”readonly maxStackDepth: number;Defined in: packages/engine/src/constants/Configuration.ts:355
Maximum stack depth (value slots) for VM execution, prevents stack overflow in recursive/pratt-parser generated bytecode