numbl 0.4.18 → 0.4.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist-browser/browser.js +1 -1
  2. package/dist-browser/numbl-core/executors/jit/callExecutor.d.ts +7 -1
  3. package/dist-browser/numbl-core/executors/jit/loopExecutor.d.ts +12 -7
  4. package/dist-browser/numbl-core/executors/jit/topLevelExecutor.d.ts +3 -0
  5. package/dist-browser/numbl-core/executors/jit/valueAdapter.d.ts +9 -2
  6. package/dist-browser/numbl-core/executors/registry.d.ts +8 -0
  7. package/dist-browser/numbl-core/interpreter/interpreter.d.ts +11 -0
  8. package/dist-browser/numbl-core/jit/builtins/runtime/system/cscalar.d.ts +4 -4
  9. package/dist-browser/numbl-core/jit/codegen/emitIndex.d.ts +1 -1
  10. package/dist-browser/numbl-core/jit/compileSpec.d.ts +4 -0
  11. package/dist-browser/numbl-core/jit/lowering/lower.d.ts +13 -0
  12. package/dist-browser/numbl-core/jitDeclineDiagnostics.d.ts +6 -0
  13. package/dist-browser/numbl-core/version.d.ts +1 -1
  14. package/dist-cli/cli.js +361 -109
  15. package/dist-lib/lib.js +298 -67
  16. package/dist-lib/numbl-core/executors/jit/callExecutor.d.ts +7 -1
  17. package/dist-lib/numbl-core/executors/jit/loopExecutor.d.ts +12 -7
  18. package/dist-lib/numbl-core/executors/jit/topLevelExecutor.d.ts +3 -0
  19. package/dist-lib/numbl-core/executors/jit/valueAdapter.d.ts +9 -2
  20. package/dist-lib/numbl-core/executors/registry.d.ts +8 -0
  21. package/dist-lib/numbl-core/interpreter/interpreter.d.ts +11 -0
  22. package/dist-lib/numbl-core/jit/builtins/runtime/system/cscalar.d.ts +4 -4
  23. package/dist-lib/numbl-core/jit/codegen/emitIndex.d.ts +1 -1
  24. package/dist-lib/numbl-core/jit/compileSpec.d.ts +4 -0
  25. package/dist-lib/numbl-core/jit/lowering/lower.d.ts +13 -0
  26. package/dist-lib/numbl-core/jitDeclineDiagnostics.d.ts +6 -0
  27. package/dist-lib/numbl-core/version.d.ts +1 -1
  28. package/dist-site-viewer/assets/{index-34LVPucU.js → index-B5Y5557F.js} +252 -252
  29. package/dist-site-viewer/assets/{numbl-worker-BCMSGYEy.js → numbl-worker-CtoT7C0f.js} +103 -87
  30. package/dist-site-viewer/index.html +1 -1
  31. package/package.json +1 -1
@@ -25,7 +25,10 @@
25
25
  * - **Loop-depth gate.** Declines when `interp.loopDepth > 0` so a
26
26
  * hot loop iterating function calls doesn't pay per-call JIT
27
27
  * propose / spec-cache overhead. Once an outer call is JIT'd, its
28
- * loops run inside mtoc2's compiled code anyway.
28
+ * loops run inside mtoc2's compiled code anyway. The gate lifts when
29
+ * every enclosing loop was itself declined: nothing above will be
30
+ * compiled then, and an expensive callee would otherwise run
31
+ * interpreted all the way down (`Interpreter.jitDeclinedLoopDepth`).
29
32
  */
30
33
  import type { Executor } from "../types.js";
31
34
  import { type JitType } from "../../jitTypes.js";
@@ -40,6 +43,9 @@ interface JitCallData {
40
43
  }
41
44
  interface CompiledArtifact {
42
45
  readonly specFn: (...args: unknown[]) => unknown;
46
+ /** The spec's declared output types — needed to convert a returned
47
+ * struct back (an untagged JS object otherwise). */
48
+ readonly outputTypes: ReadonlyArray<CompilerType>;
43
49
  }
44
50
  export declare const jitCallExecutor: Executor<JitCallData, CompiledArtifact | null>;
45
51
  export {};
@@ -9,13 +9,15 @@
9
9
  * that the synthetic body is a single-element `[loopStmt]` instead of
10
10
  * a whole script body.
11
11
  *
12
- * Loop-depth gate: only fires when `interp.loopDepth === 0`. A loop
13
- * dispatched while the interpreter is iterating an enclosing
14
- * loop-body would pay per-iter propose/cache overhead with no
15
- * speedup, because the *outer* loop is the natural JIT entry point
16
- * (it captures the inner loop's body and runs it natively in mtoc2-
17
- * emitted code). When the outer loop fires its own JIT, the inner
18
- * loop never reaches the interpreter dispatcher at all.
12
+ * Loop-depth gate: fires when `interp.loopDepth === 0`, or when every
13
+ * enclosing loop has been declined by the JIT. A loop dispatched while the
14
+ * interpreter iterates an enclosing loop-body would pay per-iter
15
+ * propose/cache overhead with no speedup, because the *outer* loop is the
16
+ * natural JIT entry point (it captures the inner loop's body and runs it
17
+ * natively in mtoc2-emitted code) — but that only holds when the outer loop
18
+ * actually compiles. If it declined, the interpreter is walking its body and
19
+ * this loop is the outermost thing still compilable, so the gate lifts
20
+ * (`Interpreter.jitDeclinedLoopDepth`).
19
21
  */
20
22
  import type { Executor } from "../types.js";
21
23
  import { type JitType } from "../../jitTypes.js";
@@ -36,6 +38,9 @@ interface JitLoopData {
36
38
  }
37
39
  interface CompiledArtifact {
38
40
  readonly specFn: (...args: unknown[]) => unknown;
41
+ /** The synthetic spec's output types, so a struct written back into the
42
+ * env is rebuilt as a struct (the emitted value is an untagged object). */
43
+ readonly outputTypes: ReadonlyArray<CompilerType>;
39
44
  }
40
45
  export declare const jitLoopExecutor: Executor<JitLoopData, CompiledArtifact | null>;
41
46
  export {};
@@ -31,6 +31,9 @@ interface JitTopLevelData {
31
31
  interface CompiledArtifact {
32
32
  readonly specFn: (...args: unknown[]) => unknown;
33
33
  readonly nargout: number;
34
+ /** The synthetic spec's output types, so a struct written back into the
35
+ * env is rebuilt as a struct (the emitted value is an untagged object). */
36
+ readonly outputTypes: ReadonlyArray<CompilerType>;
34
37
  }
35
38
  export declare const jitTopLevelExecutor: Executor<JitTopLevelData, CompiledArtifact | null>;
36
39
  export {};
@@ -43,8 +43,15 @@ import type { Type } from "../../jit/index.js";
43
43
  * complex-typed body reads `.re`/`.im`, so a bare number must be
44
44
  * boxed into `{re, im:0}`. */
45
45
  export declare function numblToJit(v: RuntimeValue, paramType?: Type): unknown;
46
- /** mtoc2 emit-JS return value → numbl RuntimeValue. */
47
- export declare function jitToNumbl(v: unknown): RuntimeValue;
46
+ /** mtoc2 emit-JS return value → numbl RuntimeValue.
47
+ *
48
+ * `retType` is the compiler type the spec declares for this output. It is
49
+ * only consulted for plain untagged objects, which is how the emitted code
50
+ * represents both a struct and a class instance — the value alone cannot
51
+ * tell them apart, so a struct is only rebuilt when the type says Struct
52
+ * and anything else untagged is rejected (the executor then bails and the
53
+ * interpreter, which has full class semantics, re-runs the call). */
54
+ export declare function jitToNumbl(v: unknown, retType?: Type): RuntimeValue;
48
55
  /** True if `e` is the grow-bail sentinel thrown by the emitted JS
49
56
  * store helpers (`mtoc2_idx_*_grow_js` in `scalar_index.js`) — an
50
57
  * indexed store whose index exceeds the runtime extent, which would
@@ -110,6 +110,14 @@ export declare class Registry {
110
110
  * pure overhead.
111
111
  */
112
112
  dispatch(siblings: readonly Stmt[], i: number, ctx: DispatchContext): DispatchResult;
113
+ /** Run one stmt on the AST interpreter.
114
+ *
115
+ * When that stmt is a loop, the interpreter is about to walk its body,
116
+ * which invalidates the "an enclosing loop will capture me" assumption
117
+ * behind the executors' `loopDepth` gate. `jitDeclinedLoopDepth` records
118
+ * that for the duration of the body so nested loops and calls can bid for
119
+ * themselves instead of running interpreted all the way down. */
120
+ private interpretFallback;
113
121
  private runStmtCandidate;
114
122
  /** Cache lookup + compile-on-miss + run + bail handling. Returns
115
123
  * the executor's success RunResult, or null when the candidate
@@ -54,6 +54,17 @@ export declare class Interpreter {
54
54
  * interpreter never sees them, so this gate only fires on calls
55
55
  * that genuinely happen at the interpreter level inside a loop. */
56
56
  loopDepth: number;
57
+ /** @internal Number of those enclosing loops that the JIT *declined*, so
58
+ * the interpreter is walking their bodies statement by statement. The
59
+ * `loopDepth > 0` gate above assumes an enclosing loop will be compiled
60
+ * and will swallow whatever is nested inside it; when that loop was
61
+ * declined instead, the assumption is false and everything below it would
62
+ * run interpreted however expensive it is. The executors therefore gate on
63
+ * `loopDepth > 0 && jitDeclinedLoopDepth === 0`: still no per-iteration JIT
64
+ * attempts underneath a loop that is about to be compiled, but a nested
65
+ * loop or call under a declined one gets its own chance. Bumped by the
66
+ * registry around the interpreter fallback for a loop stmt. */
67
+ jitDeclinedLoopDepth: number;
57
68
  /** @internal Number of enclosing conditional blocks (`if` / `switch` /
58
69
  * `try`) whose bodies the interpreter is currently executing. Used by
59
70
  * the loop classifier: when a loop is dispatched with `condBlockDepth >
@@ -34,7 +34,7 @@ export function mtoc2_cpow(a: any, b: any): {
34
34
  im: number;
35
35
  };
36
36
  export function mtoc2_csqrt(z: any): {
37
- re: number;
37
+ re: any;
38
38
  im: number;
39
39
  };
40
40
  export function mtoc2_cexp(z: any): {
@@ -42,15 +42,15 @@ export function mtoc2_cexp(z: any): {
42
42
  im: number;
43
43
  };
44
44
  export function mtoc2_clog(z: any): {
45
- re: number;
45
+ re: any;
46
46
  im: number;
47
47
  };
48
48
  export function mtoc2_clog2(z: any): {
49
- re: number;
49
+ re: any;
50
50
  im: number;
51
51
  };
52
52
  export function mtoc2_clog10(z: any): {
53
- re: number;
53
+ re: any;
54
54
  im: number;
55
55
  };
56
56
  export function mtoc2_csin(z: any): {
@@ -38,7 +38,7 @@ export declare function emitNdScalarOffset(state: RuntimeState, indices: Readonl
38
38
  * the precomputed source-index buffer). The caller is expected to
39
39
  * emit these lines immediately after closing the slot iteration
40
40
  * loops and before the GCC statement-expression's yield expression. */
41
- export declare function emitSliceSlotSetup(state: RuntimeState, lines: string[], indent: string, slotsTyped: ReadonlyArray<IndexSliceArg>, baseCName: string, cleanups?: string[]): string[];
41
+ export declare function emitSliceSlotSetup(state: RuntimeState, lines: string[], indent: string, slotsTyped: ReadonlyArray<IndexSliceArg>, baseCName: string, cleanups?: string[], grow?: boolean): string[];
42
42
  /** Emit an `IndexSlice` as a C statement-expression-style block that
43
43
  * allocates the result tensor, fills it, and evaluates to the result
44
44
  * via a comma expression. The result is consumed at an owned consume
@@ -79,6 +79,10 @@ export interface CompileSpecResult {
79
79
  source: string;
80
80
  /** Names of runtime snippets activated by emit. Diagnostic only. */
81
81
  activatedSnippets: ReadonlyArray<string>;
82
+ /** The spec's output types, in order. The host needs them to convert
83
+ * returned values back: a struct and a class instance are both plain
84
+ * JS objects in the emitted code, so only the type says which is which. */
85
+ outputTypes: ReadonlyArray<Type>;
82
86
  }
83
87
  export declare function compileSpec(args: CompileSpecArgs): CompileSpecResult;
84
88
  export {};
@@ -225,6 +225,19 @@ export declare class Lowerer {
225
225
  recordAssignment(name: string, expr: IRExpr, span: Span): Assign;
226
226
  private lowerIf;
227
227
  private lowerElseChain;
228
+ /** MATLAB `switch` lowered to the equivalent if/elseif chain.
229
+ *
230
+ * The subject is evaluated once — hoisted to a temp unless it is already a
231
+ * plain variable — and each case label becomes an equality test against it:
232
+ * `strcmp` for text, `==` for numbers. A `case {a, b}` list is the OR of
233
+ * the individual tests. Everything after that is `lowerIf`'s problem, which
234
+ * means switch inherits its branch-env merging and cond folding.
235
+ *
236
+ * Declined (leaving the unit to the interpreter, as before this existed):
237
+ * a subject that is neither a scalar number nor text, a label whose kind
238
+ * does not match the subject's, and an empty `case {}`.
239
+ */
240
+ private lowerSwitch;
228
241
  private lowerWhile;
229
242
  private lowerFor;
230
243
  lowerExpr(e: Expr): IRExpr;
@@ -23,6 +23,12 @@ export interface JitDecline {
23
23
  kind: string;
24
24
  /** Which executor declined: "jit-top-level" | "jit-call" | "jit-loop". */
25
25
  where: string;
26
+ /** Source position of the offending construct, when the thrown error
27
+ * carried one. Only used for diagnostics. */
28
+ at?: {
29
+ file: string;
30
+ start: number;
31
+ };
26
32
  }
27
33
  /** Record a swallowed JIT decline reason (called from executor catch blocks). */
28
34
  export declare function recordJitDecline(d: JitDecline): void;
@@ -1,2 +1,2 @@
1
1
  /** Numbl version, used for JIT disk cache invalidation. */
2
- export declare const NUMBL_VERSION = "0.4.18";
2
+ export declare const NUMBL_VERSION = "0.4.19";