Skip to content

VMConfig

Defined in: packages/engine/src/constants/Configuration.ts:148

Virtual Machine configuration. Controls the internal bytecode VM that executes compiled expressions.

readonly maxAllocatedElements: number;

Defined in: packages/engine/src/constants/Configuration.ts:186

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.


readonly maxCollectionSize: number;

Defined in: packages/engine/src/constants/Configuration.ts:166

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.


readonly maxFunctionCalls: number;

Defined in: packages/engine/src/constants/Configuration.ts:206

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.


readonly maxInstructions: number;

Defined in: packages/engine/src/constants/Configuration.ts:152

Maximum opcodes executed per expression, halts runaway infinite loops


readonly maxStackDepth: number;

Defined in: packages/engine/src/constants/Configuration.ts:150

Maximum stack depth (value slots) for VM execution, prevents stack overflow in recursive/pratt-parser generated bytecode