knitting 0.1.56 → 0.1.61

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 (101) hide show
  1. package/BROWSER.md +134 -0
  2. package/README.md +347 -46
  3. package/knitting.browser.d.ts +6 -0
  4. package/knitting.browser.js +1 -0
  5. package/knitting.d.ts +3 -2
  6. package/knitting.js +3 -3
  7. package/map.md +21 -9
  8. package/package.json +17 -2
  9. package/prebuilds/darwin-arm64-node-127/knitting_buffer_pointer.node +0 -0
  10. package/prebuilds/darwin-arm64-node-127/knitting_shared_memory.node +0 -0
  11. package/prebuilds/darwin-arm64-node-127/knitting_shm.node +0 -0
  12. package/prebuilds/darwin-arm64-node-137/knitting_buffer_pointer.node +0 -0
  13. package/prebuilds/darwin-arm64-node-137/knitting_shared_memory.node +0 -0
  14. package/prebuilds/darwin-arm64-node-137/knitting_shm.node +0 -0
  15. package/prebuilds/win32-x64/knitting_windows_shared_memory.dll +0 -0
  16. package/prebuilds/win32-x64-node-127/knitting_buffer_pointer.node +0 -0
  17. package/prebuilds/win32-x64-node-127/knitting_shared_memory.node +0 -0
  18. package/prebuilds/win32-x64-node-127/knitting_shm.node +0 -0
  19. package/prebuilds/win32-x64-node-137/knitting_buffer_pointer.node +0 -0
  20. package/prebuilds/win32-x64-node-137/knitting_shared_memory.node +0 -0
  21. package/prebuilds/win32-x64-node-137/knitting_shm.node +0 -0
  22. package/scripts/build-compiled-worker.ts +276 -0
  23. package/scripts/compiled-worker/porffor.d.ts +5 -0
  24. package/scripts/compiled-worker/runtime.ts +529 -0
  25. package/scripts/compiled-worker/task-shim.ts +32 -0
  26. package/src/api.d.ts +24 -1
  27. package/src/api.js +311 -27
  28. package/src/common/module-url.d.ts +1 -0
  29. package/src/common/module-url.js +30 -2
  30. package/src/common/node-compat.d.ts +2 -0
  31. package/src/common/path-canonical.js +20 -6
  32. package/src/common/runtime.d.ts +3 -1
  33. package/src/common/runtime.js +25 -4
  34. package/src/common/task-source.d.ts +2 -0
  35. package/src/common/task-source.js +17 -1
  36. package/src/common/worker-runtime.js +16 -7
  37. package/src/connections/buffer-reference-native.js +25 -1
  38. package/src/connections/buffer-reference.d.ts +23 -2
  39. package/src/connections/buffer-reference.js +143 -29
  40. package/src/connections/bun.d.ts +1 -1
  41. package/src/connections/bun.js +25 -14
  42. package/src/connections/deno.d.ts +3 -1
  43. package/src/connections/deno.js +35 -14
  44. package/src/connections/external-array-buffer.d.ts +2 -0
  45. package/src/connections/external-array-buffer.js +33 -0
  46. package/src/connections/node-addons.d.ts +11 -0
  47. package/src/connections/node-addons.js +49 -1
  48. package/src/connections/node-ffi-api.d.ts +19 -0
  49. package/src/connections/node-ffi-api.js +28 -0
  50. package/src/connections/node-ffi.d.ts +27 -0
  51. package/src/connections/node-ffi.js +262 -0
  52. package/src/connections/node.d.ts +1 -1
  53. package/src/connections/node.js +20 -20
  54. package/src/connections/package-assets.js +25 -15
  55. package/src/connections/posix.d.ts +42 -0
  56. package/src/connections/posix.js +101 -0
  57. package/src/connections/process-shared-buffer.d.ts +1 -0
  58. package/src/connections/process-shared-buffer.js +11 -45
  59. package/src/connections/types.d.ts +4 -0
  60. package/src/connections/windows.d.ts +19 -10
  61. package/src/connections/windows.js +87 -66
  62. package/src/error.d.ts +7 -6
  63. package/src/error.js +8 -7
  64. package/src/memory/lock.d.ts +112 -77
  65. package/src/memory/lock.js +314 -87
  66. package/src/memory/payloadCodec.d.ts +11 -2
  67. package/src/memory/payloadCodec.js +129 -37
  68. package/src/memory/regionRegistry.d.ts +1 -3
  69. package/src/memory/regionRegistry.js +16 -14
  70. package/src/permission/compatibility.d.ts +28 -0
  71. package/src/permission/compatibility.js +239 -0
  72. package/src/permission/index.d.ts +2 -0
  73. package/src/permission/index.js +1 -0
  74. package/src/permission/protocol.d.ts +1 -0
  75. package/src/permission/protocol.js +59 -15
  76. package/src/runtime/compiled-artifact.d.ts +21 -0
  77. package/src/runtime/compiled-artifact.js +260 -0
  78. package/src/runtime/compiled-builder.d.ts +8 -0
  79. package/src/runtime/compiled-builder.js +42 -0
  80. package/src/runtime/compiled-worker.d.ts +27 -0
  81. package/src/runtime/compiled-worker.js +562 -0
  82. package/src/runtime/dispatcher.js +9 -0
  83. package/src/runtime/inline-executor.js +27 -15
  84. package/src/runtime/pool.d.ts +121 -5
  85. package/src/runtime/pool.js +263 -49
  86. package/src/runtime/process-worker.d.ts +3 -13
  87. package/src/runtime/process-worker.js +97 -101
  88. package/src/runtime/tx-queue.d.ts +18 -2
  89. package/src/runtime/tx-queue.js +56 -16
  90. package/src/runtime/worker-common.d.ts +13 -0
  91. package/src/runtime/worker-common.js +102 -0
  92. package/src/types.d.ts +89 -9
  93. package/src/worker/composable-runners.js +3 -2
  94. package/src/worker/loop.d.ts +1 -0
  95. package/src/worker/loop.js +52 -17
  96. package/src/worker/rx-queue.d.ts +11 -1
  97. package/src/worker/rx-queue.js +4 -1
  98. package/src/worker/task-loader.d.ts +5 -4
  99. package/src/worker/task-loader.js +13 -7
  100. package/src/worker/timers.d.ts +8 -1
  101. package/src/worker/timers.js +28 -23
@@ -1,27 +1,37 @@
1
1
  import { withResolvers } from "../common/with-resolvers.js";
2
2
  import RingQueue from "../ipc/tools/ring-queue.js";
3
3
  import { createRuntimeMessageChannel } from "../common/worker-runtime.js";
4
+ // const objects, not `enum`s: Andromeda's Nova engine can't parse `enum`. Same
5
+ // values and emit on Node/Deno/Bun.
6
+ const SlotStateMacro = {
7
+ Free: -1,
8
+ Pending: 0,
9
+ };
10
+ const TimeoutKind = {
11
+ Reject: 0,
12
+ Resolve: 1,
13
+ };
4
14
  const normalizeTimeout = (timeout) => {
5
15
  if (timeout == null)
6
16
  return undefined;
7
17
  if (typeof timeout === "number") {
8
18
  return timeout >= 0
9
- ? { ms: timeout, kind: 0 /* TimeoutKind.Reject */, value: new Error("Task timeout") }
19
+ ? { ms: timeout, kind: TimeoutKind.Reject, value: new Error("Task timeout") }
10
20
  : undefined;
11
21
  }
12
22
  const ms = timeout.time;
13
23
  if (!(ms >= 0))
14
24
  return undefined;
15
25
  if ("default" in timeout) {
16
- return { ms, kind: 1 /* TimeoutKind.Resolve */, value: timeout.default };
26
+ return { ms, kind: TimeoutKind.Resolve, value: timeout.default };
17
27
  }
18
28
  if (timeout.maybe === true) {
19
- return { ms, kind: 1 /* TimeoutKind.Resolve */, value: undefined };
29
+ return { ms, kind: TimeoutKind.Resolve, value: undefined };
20
30
  }
21
31
  if ("error" in timeout) {
22
- return { ms, kind: 0 /* TimeoutKind.Reject */, value: timeout.error };
32
+ return { ms, kind: TimeoutKind.Reject, value: timeout.error };
23
33
  }
24
- return { ms, kind: 0 /* TimeoutKind.Reject */, value: new Error("Task timeout") };
34
+ return { ms, kind: TimeoutKind.Reject, value: new Error("Task timeout") };
25
35
  };
26
36
  const raceTimeout = (promise, spec) => new Promise((resolve, reject) => {
27
37
  let done = false;
@@ -29,7 +39,7 @@ const raceTimeout = (promise, spec) => new Promise((resolve, reject) => {
29
39
  if (done)
30
40
  return;
31
41
  done = true;
32
- if (spec.kind === 1 /* TimeoutKind.Resolve */) {
42
+ if (spec.kind === TimeoutKind.Resolve) {
33
43
  resolve(spec.value);
34
44
  }
35
45
  else {
@@ -52,8 +62,10 @@ const raceTimeout = (promise, spec) => new Promise((resolve, reject) => {
52
62
  });
53
63
  const INLINE_ABORT_TOOLKIT = (() => {
54
64
  const hasAborted = () => false;
65
+ const now = () => performance.now();
55
66
  return {
56
67
  hasAborted,
68
+ now,
57
69
  };
58
70
  })();
59
71
  const composeInlineCallable = (fn, timeout, useAbortToolkit = false) => {
@@ -86,7 +98,7 @@ export const createInlineExecutor = ({ tasks, genTaskID, batchSize, }) => {
86
98
  });
87
99
  const initCap = 16;
88
100
  let fnByIndex = new Int32Array(initCap);
89
- let stateByIndex = new Int8Array(initCap).fill(-1 /* SlotStateMacro.Free */);
101
+ let stateByIndex = new Int8Array(initCap).fill(SlotStateMacro.Free);
90
102
  let argsByIndex = new Array(initCap);
91
103
  let taskIdByIndex = new Array(initCap).fill(-1);
92
104
  let deferredByIndex = new Array(initCap);
@@ -126,13 +138,13 @@ export const createInlineExecutor = ({ tasks, genTaskID, batchSize, }) => {
126
138
  send();
127
139
  };
128
140
  const enqueueIfCurrent = (index, taskID) => {
129
- if (stateByIndex[index] !== 0 /* SlotStateMacro.Pending */ ||
141
+ if (stateByIndex[index] !== SlotStateMacro.Pending ||
130
142
  taskIdByIndex[index] !== taskID)
131
143
  return;
132
144
  enqueue(index);
133
145
  };
134
146
  const settleIfCurrent = (index, taskID, isError, value) => {
135
- if (stateByIndex[index] !== 0 /* SlotStateMacro.Pending */ ||
147
+ if (stateByIndex[index] !== SlotStateMacro.Pending ||
136
148
  taskIdByIndex[index] !== taskID)
137
149
  return;
138
150
  const deferred = deferredByIndex[index];
@@ -153,7 +165,7 @@ export const createInlineExecutor = ({ tasks, genTaskID, batchSize, }) => {
153
165
  nextFnByIndex.set(fnByIndex);
154
166
  fnByIndex = nextFnByIndex;
155
167
  const nextStateByIndex = new Int8Array(newCap);
156
- nextStateByIndex.fill(-1 /* SlotStateMacro.Free */);
168
+ nextStateByIndex.fill(SlotStateMacro.Free);
157
169
  nextStateByIndex.set(stateByIndex);
158
170
  stateByIndex = nextStateByIndex;
159
171
  argsByIndex.length = newCap;
@@ -172,7 +184,7 @@ export const createInlineExecutor = ({ tasks, genTaskID, batchSize, }) => {
172
184
  if (maybeIndex === undefined)
173
185
  break;
174
186
  const index = maybeIndex | 0;
175
- if (stateByIndex[index] !== 0 /* SlotStateMacro.Pending */)
187
+ if (stateByIndex[index] !== SlotStateMacro.Pending)
176
188
  continue;
177
189
  const taskID = taskIdByIndex[index];
178
190
  try {
@@ -213,7 +225,7 @@ export const createInlineExecutor = ({ tasks, genTaskID, batchSize, }) => {
213
225
  }
214
226
  function cleanup(index) {
215
227
  working--;
216
- stateByIndex[index] = -1 /* SlotStateMacro.Free */;
228
+ stateByIndex[index] = SlotStateMacro.Free;
217
229
  fnByIndex[index] = 0;
218
230
  taskIdByIndex[index] = -1;
219
231
  argsByIndex[index] = undefined;
@@ -230,7 +242,7 @@ export const createInlineExecutor = ({ tasks, genTaskID, batchSize, }) => {
230
242
  argsByIndex[index] = args;
231
243
  fnByIndex[index] = fnNumber | 0;
232
244
  deferredByIndex[index] = deferred;
233
- stateByIndex[index] = 0 /* SlotStateMacro.Pending */;
245
+ stateByIndex[index] = SlotStateMacro.Pending;
234
246
  working++;
235
247
  if (args instanceof Promise) {
236
248
  args.then((value) => {
@@ -250,7 +262,7 @@ export const createInlineExecutor = ({ tasks, genTaskID, batchSize, }) => {
250
262
  return {
251
263
  kills: async () => {
252
264
  for (let index = 0; index < stateByIndex.length; index++) {
253
- if (stateByIndex[index] !== 0 /* SlotStateMacro.Pending */)
265
+ if (stateByIndex[index] !== SlotStateMacro.Pending)
254
266
  continue;
255
267
  try {
256
268
  deferredByIndex[index]?.reject("Thread closed");
@@ -271,7 +283,7 @@ export const createInlineExecutor = ({ tasks, genTaskID, batchSize, }) => {
271
283
  taskIdByIndex.fill(-1);
272
284
  deferredByIndex.fill(undefined);
273
285
  fnByIndex.fill(0);
274
- stateByIndex.fill(-1 /* SlotStateMacro.Free */);
286
+ stateByIndex.fill(SlotStateMacro.Free);
275
287
  working = 0;
276
288
  isInMacro = false;
277
289
  isInMicro = false;
@@ -1,11 +1,104 @@
1
+ import { createHostTxQueue } from "./tx-queue.js";
1
2
  import { type ProcessSharedMemoryBacking } from "./process-worker.js";
2
3
  import { type Sab } from "../ipc/transport/shared-memory.js";
3
4
  import { ChannelHandler, type DispatcherCheck } from "./dispatcher.js";
4
- import { lock2 } from "../memory/lock.js";
5
- import type { DebugOptions, DispatcherSettings, WorkerContext, WorkerData, WorkerSettings } from "../types.js";
5
+ import { lock2, type Task } from "../memory/lock.js";
6
+ import "../memory/payloadCodec.js";
7
+ import type { DebugOptions, DispatcherSettings, LockBuffers, WorkerContext, WorkerData, WorkerSettings } from "../types.js";
6
8
  import "../worker/loop.js";
7
9
  import { type PayloadBufferOptions } from "../memory/payload-config.js";
8
- export declare const spawnWorkerContext: ({ list, ids, names, sab, thread, debug, hostDebug, totalNumberOfThread, source, at, workerOptions, workerExecArgv, permission, host, payload, bufferReferenceReturn, abortSignalCapacity, usesAbortSignal, sharedChannelHandler, }: {
10
+ /**
11
+ * Build the buffers, host-side locks and pending registry that a stealing pool
12
+ * shares. One submit region for every worker to claim from, one private return
13
+ * region per worker, and a single pool-global queue so a response arriving on
14
+ * any lane settles the right promise.
15
+ *
16
+ * Region width follows paper §6.1: the largest power-of-two `g` leaving a spare
17
+ * region for a delayed claimant (`slots / g >= consumers + 1`). At 32 slots that
18
+ * caps how wide a region can be well before it caps the worker count.
19
+ */
20
+ export declare const resolveStealRegionLanes: (consumers: number) => number;
21
+ /** Maximum claimants that leave the protocol's required spare region. */
22
+ export declare const MAX_STEAL_CONSUMERS: number;
23
+ export declare const createStealPoolBuffers: ({ threads, payload, regionLanes, abortSignalCapacity, usesAbortSignal, }: {
24
+ threads: number;
25
+ payload?: PayloadBufferOptions;
26
+ regionLanes?: number;
27
+ abortSignalCapacity?: number;
28
+ usesAbortSignal?: boolean;
29
+ }) => {
30
+ submitBuffers: LockBuffers;
31
+ returnBuffers: LockBuffers[];
32
+ hostSubmitLock: {
33
+ enlist: (task: Task) => true;
34
+ encode: (task: Task, state?: number) => boolean;
35
+ encodeManyFrom: (list: import("../ipc/tools/ring-queue.js").default<Task>) => number;
36
+ encodeAll: () => boolean;
37
+ publish: (task: Task) => boolean;
38
+ flushPending: () => boolean;
39
+ decode: () => boolean;
40
+ hasSpace: () => boolean;
41
+ resolved: import("../ipc/tools/ring-queue.js").default<Task>;
42
+ hostBits: Int32Array<import("../common/shared-buffer-region.js").SharedBuffer>;
43
+ workerBits: Int32Array<import("../common/shared-buffer-region.js").SharedBuffer>;
44
+ recyclecList: import("../ipc/tools/ring-queue.js").default<Task>;
45
+ resolveHost: ({ queue, onResolved, shouldSettle, activeRejectPlaceholder, }: {
46
+ queue: Task[];
47
+ onResolved?: (task: Task) => void;
48
+ shouldSettle?: (task: Task) => boolean;
49
+ activeRejectPlaceholder?: Task["reject"];
50
+ }) => () => number;
51
+ hasPendingFrames: () => boolean;
52
+ getPendingFrameCount: () => number;
53
+ getPendingPromiseCount: () => number;
54
+ resetPendingState: () => void;
55
+ deactivateStealConsumer: (id: number) => boolean;
56
+ takeDeferredCount: () => number;
57
+ setPromiseHandler: (handler?: import("../memory/lock.js").PromisePayloadHandler) => void;
58
+ };
59
+ hostReturnLocks: {
60
+ enlist: (task: Task) => true;
61
+ encode: (task: Task, state?: number) => boolean;
62
+ encodeManyFrom: (list: import("../ipc/tools/ring-queue.js").default<Task>) => number;
63
+ encodeAll: () => boolean;
64
+ publish: (task: Task) => boolean;
65
+ flushPending: () => boolean;
66
+ decode: () => boolean;
67
+ hasSpace: () => boolean;
68
+ resolved: import("../ipc/tools/ring-queue.js").default<Task>;
69
+ hostBits: Int32Array<import("../common/shared-buffer-region.js").SharedBuffer>;
70
+ workerBits: Int32Array<import("../common/shared-buffer-region.js").SharedBuffer>;
71
+ recyclecList: import("../ipc/tools/ring-queue.js").default<Task>;
72
+ resolveHost: ({ queue, onResolved, shouldSettle, activeRejectPlaceholder, }: {
73
+ queue: Task[];
74
+ onResolved?: (task: Task) => void;
75
+ shouldSettle?: (task: Task) => boolean;
76
+ activeRejectPlaceholder?: Task["reject"];
77
+ }) => () => number;
78
+ hasPendingFrames: () => boolean;
79
+ getPendingFrameCount: () => number;
80
+ getPendingPromiseCount: () => number;
81
+ resetPendingState: () => void;
82
+ deactivateStealConsumer: (id: number) => boolean;
83
+ takeDeferredCount: () => number;
84
+ setPromiseHandler: (handler?: import("../memory/lock.js").PromisePayloadHandler) => void;
85
+ }[];
86
+ sharedQueue: {
87
+ rejectAll: (reason: string) => void;
88
+ hasPendingFrames: () => boolean;
89
+ txIdle: () => boolean;
90
+ completeFrame: () => number;
91
+ setReturnHooks: (lane: number, hooks: (import("../connections/buffer-reference.js").BufferReferenceReturnHooks | ((token: bigint) => void)) | undefined) => void;
92
+ enqueue: (functionID: number, timeout?: import("../types.js").TaskTimeout, abortSignal?: import("../types.js").AbortSignalOption) => (rawArgs: unknown) => Promise<never> | import("../common/with-resolvers.js").PromiseWithMaybeReject<unknown>;
93
+ flushToWorker: () => boolean;
94
+ enqueueKnown: (task: Task) => boolean;
95
+ settlePromisePayload: (task: Task, isRejected: boolean, value: unknown) => boolean;
96
+ };
97
+ regionLanes: number;
98
+ abortSignalSAB: SharedArrayBuffer;
99
+ abortSignalMax: number;
100
+ };
101
+ export declare const spawnWorkerContext: ({ list, ids, names, sab, thread, debug, hostDebug, totalNumberOfThread, source, at, workerOptions, workerExecArgv, permission, host, payload, bufferReferenceReturn, abortSignalCapacity, usesAbortSignal, sharedChannelHandler, stealPool, }: {
9
102
  list: string[];
10
103
  ids: number[];
11
104
  names: string[];
@@ -29,11 +122,34 @@ export declare const spawnWorkerContext: ({ list, ids, names, sab, thread, debug
29
122
  * macro channel that runs all lane checks.
30
123
  */
31
124
  sharedChannelHandler?: ChannelHandler;
32
- }) => WorkerContext & {
125
+ /**
126
+ * Work-stealing wiring. When present the submit region, both host-side locks
127
+ * and the pending registry are owned by `createPool` and shared: every worker
128
+ * claims from one request region, and the host demultiplexes responses by
129
+ * task id. This lane only contributes its private return region and its
130
+ * worker. The dispatcher is owned by the pool too, so none is built here.
131
+ */
132
+ stealPool?: {
133
+ submitBuffers: LockBuffers;
134
+ returnBuffers: LockBuffers;
135
+ hostSubmitLock: ReturnType<typeof lock2>;
136
+ hostReturnLock: ReturnType<typeof lock2>;
137
+ sharedQueue: ReturnType<typeof createHostTxQueue>;
138
+ consumers: number;
139
+ consumerId: number;
140
+ regionLanes: number;
141
+ abortSignalSAB?: LockBuffers["headers"];
142
+ abortSignalMax?: number;
143
+ };
144
+ }) => (WorkerContext & {
145
+ dispatcherCheck?: never;
146
+ laneWake?: never;
147
+ bindSend?: never;
148
+ }) | (WorkerContext & {
33
149
  lock: ReturnType<typeof lock2>;
34
150
  processSharedMemoryBackings?: readonly ProcessSharedMemoryBacking[];
35
151
  dispatcherCheck?: DispatcherCheck;
36
152
  laneWake?: () => void;
37
153
  bindSend?: (fn: () => void) => void;
38
- };
154
+ });
39
155
  export type CreateContext = WorkerContext;