diff --git a/packages/compiler/src/backend/emission/emit-exprs.ts b/packages/compiler/src/backend/emission/emit-exprs.ts index 9b482e749..51b03c44a 100644 --- a/packages/compiler/src/backend/emission/emit-exprs.ts +++ b/packages/compiler/src/backend/emission/emit-exprs.ts @@ -203,7 +203,7 @@ function streamTypedRefAdapter( ` ScrDyn *d = scr_dyn_new_arr();`, ` for (size_t sc_i = 0; sc_i < v->len; sc_i++) {`, ); - if (elem.kind === "f64") { + if (elem.kind === "f64" || elem.kind === "date") { lines.push( ` scr_dyn_arr_push(d, ${box(elem, "scr_arr_get_f64(v, (double)sc_i)")});`, ); @@ -384,7 +384,7 @@ function streamFromArrayAdapter( ); } d.push(`${sig} { /* ReadableStream.from array<${key}> */`); - if (elem.kind === "f64") { + if (elem.kind === "f64" || elem.kind === "date") { d.push( ` return ${E.toDynHelper(elem)}(scr_arr_get_f64(sc_a, sc_i));`, ); @@ -3004,7 +3004,7 @@ export function emitExpr(E: CEmitter, e: IrExpr): Temp { if (e.type.inner.kind !== "array") throw new InternalCompilerError("emitter bug: promise.all result"); const elem = e.type.inner.elem; const store = - elem.kind === "f64" + (elem.kind === "f64" || elem.kind === "date") ? "scr_promise_all_store_f64" : elem.kind === "bool" ? "scr_promise_all_store_bool" @@ -7438,6 +7438,8 @@ export function emitExpr(E: CEmitter, e: IrExpr): Temp { const v = E.emitExpr(e.value); switch (e.value.type.kind) { case "f64": + case "date": + // Date crossing IN: passed as millisecond timestamp (a JS number). return E.newTemp(e.type, `scr_jsval_from_f64(${v.name})`); case "bool": return E.newTemp(e.type, `scr_jsval_from_bool(${v.name})`); diff --git a/packages/compiler/src/backend/emission/emit-types.ts b/packages/compiler/src/backend/emission/emit-types.ts index bf7b74742..60e3b541b 100644 --- a/packages/compiler/src/backend/emission/emit-types.ts +++ b/packages/compiler/src/backend/emission/emit-types.ts @@ -264,6 +264,8 @@ export function elemKindC(elem: IrType): string { } switch (elem.kind) { case "f64": + // Dates are epoch-ms f64 scalars at the C level — use the same slot. + case "date": return "SCR_ELEM_F64"; case "bool": return "SCR_ELEM_BOOL"; @@ -303,7 +305,6 @@ export function elemKindC(elem: IrType): string { // pointer identity — exactly JS function identity. case "func": return "SCR_ELEM_REF"; - case "date": case "procStream": case "undefinedT": case "nullT": @@ -381,7 +382,8 @@ export const DV_SET_KIND_C: Record = { /** Runtime accessor suffix for an element type: arrays store f64 and bool * unboxed and everything refcounted as a pointer (`_ref`). */ export function elemAccess(elem: IrType): "f64" | "bool" | "ref" { - return elem.kind === "f64" ? "f64" : elem.kind === "bool" ? "bool" : "ref"; + // Dates are stored as epoch-ms f64 scalars at the C level. + return (elem.kind === "f64" || elem.kind === "date") ? "f64" : elem.kind === "bool" ? "bool" : "ref"; } /** Runtime suffix for a map's KEY kind (f64 with SameValueZero, or string diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 72797369e..4c5cf85b2 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -7812,6 +7812,8 @@ class LlEmitter { }; switch (e.value.type.kind) { case "f64": + case "date": + // Date crossing IN: passed as millisecond timestamp (a JS number). return simple("scr_jsval_from_f64", "double", false); case "bool": return simple("scr_jsval_from_bool", "i1", false); diff --git a/packages/compiler/src/backend/llvm/shapes.ts b/packages/compiler/src/backend/llvm/shapes.ts index 2acc10a21..232338655 100644 --- a/packages/compiler/src/backend/llvm/shapes.ts +++ b/packages/compiler/src/backend/llvm/shapes.ts @@ -265,13 +265,15 @@ export function traceArg(host: ShapeHost, t: IrType): string { /** Runtime accessor suffix for an element type (matches emit-types.ts: * f64 and bool unboxed, everything refcounted through the `_ref` family). */ export function elemAccess(elem: IrType): "f64" | "bool" | "ref" { - return elem.kind === "f64" ? "f64" : elem.kind === "bool" ? "bool" : "ref"; + return (elem.kind === "f64" || elem.kind === "date") ? "f64" : elem.kind === "bool" ? "bool" : "ref"; } /** The ScrElemKind constant for the plain (non-REF) construction path. */ function elemKindNum(elem: IrType): number { switch (elem.kind) { case "f64": + // Dates are epoch-ms f64 scalars at the C level — same slot kind. + case "date": return 0; // SCR_ELEM_F64 case "bool": return 1; // SCR_ELEM_BOOL diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 22a7814ed..b9c65e810 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -6109,9 +6109,10 @@ export class Lowerer { jsvalLiftable(t: IrType, visiting: Set = new Set()): boolean { if (t.kind === "jsval") return true; if (this.boundarySafe(t)) return true; - // Typed arrays and URLs marshal IN without joining the round-trip - // (JSON) set: an engine typed-array copy / an engine URL from href. - if (t.kind === "bytes" || t.kind === "url") return true; + // Typed arrays, URLs, and Dates marshal IN without joining the round-trip + // (JSON) set: an engine typed-array copy / an engine URL from href / + // a Date as its millisecond timestamp (scr_jsval_from_f64). + if (t.kind === "bytes" || t.kind === "url" || t.kind === "date") return true; // Checked-dynamic values deep-copy in (scr_jsval_from_dyn — data // kinds; a boxed function/handle/promise throws at runtime). if (t.kind === "dyn") return true; @@ -6162,7 +6163,7 @@ export class Lowerer { if (this.boundarySafe(e.type)) { return { kind: "jsMarshal", value: e, type: JSVAL, loc }; } - if (e.type.kind === "bytes" || e.type.kind === "url") { + if (e.type.kind === "bytes" || e.type.kind === "url" || e.type.kind === "date") { return { kind: "jsMarshal", value: e, type: JSVAL, loc }; } if (e.type.kind === "record") { diff --git a/packages/compiler/src/ir/nodes.ts b/packages/compiler/src/ir/nodes.ts index 61b0fbc75..0e8eea596 100644 --- a/packages/compiler/src/ir/nodes.ts +++ b/packages/compiler/src/ir/nodes.ts @@ -518,6 +518,9 @@ export function isSupportedArrayElem(t: IrType): boolean { case "netServer": case "symbol": case "classval": + // Dates are scalar f64 (epoch-ms) at the C level — stored in SCR_ELEM_F64 + // slots. Array element reads re-box the ms value into a date handle. + case "date": return true; default: return false;