Skip to content

Phase 6 Technical Specification: Strict C-Style Rules for the JS Engine (V1) ​

1. Executive Summary & Core Philosophy ​

To guarantee that Version 1 (JavaScript/TypeScript Reference Engine) can be replaced by Version 2 (Compiled C/WebAssembly) as a seamless drop-in swap with zero architectural friction, all code inside src/engine/ must strictly adhere to C-Style Semantics.

Writing V1 in C-style JS delivers three enormous advantages:

  1. 1:1 Porting Parity: Porting from V1 JS to V2 C is a mechanical, line-by-line syntax translation (from view.getInt32(ptr, true) to *(int32_t*)ptr).
  2. Zero Garbage Collection (GC) Jitter: Banning dynamic object creation in the execution loop completely eliminates V8 GC pauses, providing microsecond-level query latencies.
  3. Bit-for-Bit Differential Testing: Both engines operate on identical byte patterns in shared memory, allowing the differential test runner to assert bitwise identical slotted pages.

2. The Five Strict Rules of Engine Core Development ​

Rule 1: Zero Dynamic Object Allocation in Execution Hot Paths ​

  • Banned Constructs inside src/engine/ hot loops:
    • new Map(), new Set(), new Object()
    • Object literals ({ id: 1, name: 'foo' })
    • Array literals inside loops ([a, b, c])
    • Class instantiations (new Cursor())
  • Required Approach: All state, cursors, registers, and temporary tables live inside pre-allocated slices of ArrayBuffer or the Transient Query Arena.

Rule 2: Pure Numeric FFI Signatures ​

All engine entry points must accept and return only primitive numbers (pointers, byte offsets, lengths, status codes), identical to WebAssembly exported function signatures:

typescript
// ALLOWED: Matches Wasm ABI
function vm_step(ctxOffset: number): number;
function page_init(pageOffset: number, pageType: number): void;
function page_insert_cell(pageOffset: number, cellOffset: number, cellLen: number): number;

// STRICTLY BANNED: Passes JS object across boundary
function vm_step(ctx: VmContextObject): QueryResultObject;

Rule 3: Manual Byte Layouts & Explicit Little-Endian DataView ​

Struct field dereferencing must be written with explicit byte offsets and little-endian indicators:

typescript
// V1 JavaScript (C-Style):
function get_cell_offset(view: DataView, pageOffset: number, slotIdx: number): number {
  return view.getUint16(pageOffset + 12 + (slotIdx * 2), true);
}

// V2 C (Drop-in Port):
static inline uint16_t get_cell_offset(const uint8_t *page, uint16_t slot_idx) {
  return *(const uint16_t*)(page + 12 + (slot_idx * 2));
}

Rule 4: Iterative Only (No Call-Stack Recursion) ​

  • The call stack in src/engine/ must never exceed 1 function deep (vm_step()).
  • B-Tree Traversal: Traversal of internal nodes, page descend, and leaf sibling navigation must use an explicit array stack (cursors[16]) stored in VmContext.
  • Zero Recursion: Recursive tree search algorithms are strictly forbidden because they trap execution state on the C call stack, preventing pause/resume on async page faults.

Rule 5: Primitive Bitwise Bitmasks ​

Flags, nullability, and dirty tracking must use native bitwise operations:

typescript
// Check if column i is NULL:
const isNull = (view.getUint8(nullBitmapOffset + (colIdx >> 3)) & (1 << (colIdx & 7))) !== 0;

// Mark slot S dirty:
dirtyMask[slot >> 3] |= (1 << (slot & 7));

3. Side-by-Side Translation Reference (JS ↔ C) ​

OperationV1 Implementation (TypeScript / JS)V2 Implementation (C99 / Wasm)
Read uint16view.getUint16(offset, true)*(const uint16_t*)(ptr + offset)
Write uint32view.setUint32(offset, val, true)*(uint32_t*)(ptr + offset) = val;
Read float64view.getFloat64(offset, true)*(const double*)(ptr + offset)
Memory Copyuint8.set(srcSlice, targetOffset)memcpy(dest, src, length)
Zero Filluint8.fill(0, start, end)memset(dest, 0, length)
Null Test(bitmap[i >> 3] & (1 << (i & 7))) !== 0(bitmap[i >> 3] & (1 << (i & 7))) != 0

4. Automated Linting & CI Verification ​

To ensure that no dynamic JS object allocations slip into the engine core:

  1. Static Analysis Rule: Custom ESLint rule scanning src/engine/vm.ts and src/engine/page.ts for object literals (ObjectExpression) and NewExpression (except pre-allocated buffers at initialization).
  2. Allocation Profiling Test: Integration test running 100,000 query cycles while monitoring V8 heap metrics (performance.memory.usedJSHeapSize); asserts zero heap allocation growth during the query loop.

5. Verification & Test Suite (tests/c_style_invariants.test.ts) ​

  1. Zero-Allocation Loop Verification: Run 10,000 scans; assert V8 garbage collection is never triggered.
  2. Numeric Signature Parity: Assert all engine exports accept and return exclusively numeric primitives.
  3. Little-Endian Consistency: Assert all multi-byte read/write operations specify little-endian byte ordering.

Released under the MIT License.