@cheatron/nthread 1.0.0

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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +175 -0
  3. package/dist/crt.d.ts +24 -0
  4. package/dist/crt.d.ts.map +1 -0
  5. package/dist/crt.js +28 -0
  6. package/dist/crt.js.map +1 -0
  7. package/dist/errors.d.ts +50 -0
  8. package/dist/errors.d.ts.map +1 -0
  9. package/dist/errors.js +84 -0
  10. package/dist/errors.js.map +1 -0
  11. package/dist/globals.d.ts +48 -0
  12. package/dist/globals.d.ts.map +1 -0
  13. package/dist/globals.js +132 -0
  14. package/dist/globals.js.map +1 -0
  15. package/dist/index.d.ts +12 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +12 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/logger.d.ts +2 -0
  20. package/dist/logger.d.ts.map +1 -0
  21. package/dist/logger.js +3 -0
  22. package/dist/logger.js.map +1 -0
  23. package/dist/memory/alloc-options.d.ts +23 -0
  24. package/dist/memory/alloc-options.d.ts.map +1 -0
  25. package/dist/memory/alloc-options.js +1 -0
  26. package/dist/memory/alloc-options.js.map +1 -0
  27. package/dist/memory/heap.d.ts +147 -0
  28. package/dist/memory/heap.d.ts.map +1 -0
  29. package/dist/memory/heap.js +276 -0
  30. package/dist/memory/heap.js.map +1 -0
  31. package/dist/memory/romem.d.ts +69 -0
  32. package/dist/memory/romem.d.ts.map +1 -0
  33. package/dist/memory/romem.js +108 -0
  34. package/dist/memory/romem.js.map +1 -0
  35. package/dist/nthread-heap.d.ts +65 -0
  36. package/dist/nthread-heap.d.ts.map +1 -0
  37. package/dist/nthread-heap.js +193 -0
  38. package/dist/nthread-heap.js.map +1 -0
  39. package/dist/nthread.d.ts +146 -0
  40. package/dist/nthread.d.ts.map +1 -0
  41. package/dist/nthread.js +421 -0
  42. package/dist/nthread.js.map +1 -0
  43. package/dist/thread/captured-thread.d.ts +68 -0
  44. package/dist/thread/captured-thread.d.ts.map +1 -0
  45. package/dist/thread/captured-thread.js +167 -0
  46. package/dist/thread/captured-thread.js.map +1 -0
  47. package/dist/thread/proxy-thread.d.ts +92 -0
  48. package/dist/thread/proxy-thread.d.ts.map +1 -0
  49. package/dist/thread/proxy-thread.js +154 -0
  50. package/dist/thread/proxy-thread.js.map +1 -0
  51. package/package.json +57 -0
@@ -0,0 +1,23 @@
1
+ import type * as Native from '@cheatron/native';
2
+ /** Options for ProxyThread.alloc(). */
3
+ export interface AllocOptions {
4
+ /**
5
+ * Fill byte applied after allocation.
6
+ * - `undefined` → no explicit fill
7
+ * - `0` → zero fill (uses `calloc` for raw malloc fallback; explicit memset for heap)
8
+ * - `N` → fill entire block with `N & 0xff`
9
+ */
10
+ fill?: number;
11
+ /**
12
+ * Allocate from the romem-tracked readonly zone of the heap.
13
+ * Default: `false` (readwrite zone). Ignored when falling back to raw malloc.
14
+ */
15
+ readonly?: boolean;
16
+ /**
17
+ * If provided, realloc mode: resize this existing allocation to `size` bytes.
18
+ * - Heap-backed: allocate new block → copy old data → free old block.
19
+ * - malloc-backed (or unknown): delegates to `msvcrt!realloc`.
20
+ */
21
+ address?: Native.NativePointer;
22
+ }
23
+ //# sourceMappingURL=alloc-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alloc-options.d.ts","sourceRoot":"","sources":["../../src/memory/alloc-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAEhD,uCAAuC;AACvC,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,aAAa,CAAC;CAChC"}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=alloc-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alloc-options.js","sourceRoot":"","sources":["../../src/memory/alloc-options.ts"],"names":[],"mappings":""}
@@ -0,0 +1,147 @@
1
+ import * as Native from '@cheatron/native';
2
+ import type { ProxyThread } from '../thread/proxy-thread.js';
3
+ import { type ReadOnlyMemory } from './romem.js';
4
+ /** Default total heap size (bytes) */
5
+ export declare const DEFAULT_HEAP_SIZE = 16384;
6
+ /** Result of a heap allocation — pointer into the pre-allocated region */
7
+ export interface HeapAlloc {
8
+ /** Remote address in the target process */
9
+ readonly remote: Native.NativePointer;
10
+ /** Size of this allocation */
11
+ readonly size: number;
12
+ }
13
+ /**
14
+ * A lightweight allocator that pre-allocates a single contiguous block
15
+ * in the target process and carves out sub-allocations from it.
16
+ *
17
+ * The block is split into two zones:
18
+ * - **Readonly zone** (first half): registered as romem — writes automatically
19
+ * skip unchanged bytes via snapshot diffing.
20
+ * - **ReadWrite zone** (second half): standard memory — no snapshot tracking.
21
+ *
22
+ * Supports `free()` — freed blocks are returned to a per-zone free list
23
+ * with automatic coalescing of adjacent blocks. New allocations check the
24
+ * free list first (first-fit), then fall back to bumping.
25
+ *
26
+ * ```
27
+ * ┌──────────────────────────────────────────┐
28
+ * │ base │
29
+ * │ ├── readonly zone (roSize bytes) │
30
+ * │ │ ├── alloc 1 │
31
+ * │ │ ├── [freed → free list] │
32
+ * │ │ ├── alloc 3 │
33
+ * │ │ └── ... (bump / reuse →) │
34
+ * │ ├── readwrite zone (rwSize bytes) │
35
+ * │ │ ├── alloc 1 │
36
+ * │ │ ├── [freed → free list] │
37
+ * │ │ └── ... (bump / reuse →) │
38
+ * └──────────────────────────────────────────┘
39
+ * ```
40
+ */
41
+ export declare class Heap {
42
+ /** Base remote address of the entire heap block */
43
+ readonly base: Native.NativePointer;
44
+ /** Total size of the heap */
45
+ readonly totalSize: number;
46
+ /** Size of the readonly zone */
47
+ readonly roSize: number;
48
+ /** Size of the readwrite zone */
49
+ readonly rwSize: number;
50
+ /** The romem handle for the readonly zone */
51
+ readonly romem: ReadOnlyMemory;
52
+ /** Current bump offset within the readonly zone */
53
+ private roOffset;
54
+ /** Current bump offset within the readwrite zone */
55
+ private rwOffset;
56
+ /** Free list for the readonly zone (sorted by offset) */
57
+ private roFreeList;
58
+ /** Free list for the readwrite zone (sorted by offset) */
59
+ private rwFreeList;
60
+ private constructor();
61
+ /**
62
+ * Creates a new Heap by allocating a single contiguous block in the target
63
+ * process via `calloc`. The block is zero-initialized.
64
+ *
65
+ * @param proxy The proxy thread to execute calloc on.
66
+ * @param totalSize Total heap size in bytes (default: 16384).
67
+ * @param roSize Size of the readonly zone (default: half of totalSize).
68
+ * @returns A ready-to-use Heap instance.
69
+ */
70
+ static create(proxy: ProxyThread, totalSize?: number, roSize?: number): Promise<Heap>;
71
+ /** Remote address where the readwrite zone starts */
72
+ get rwBase(): Native.NativePointer;
73
+ /** Remaining bytes in the readonly zone (bump area only, excludes free list) */
74
+ get roRemaining(): number;
75
+ /** Remaining bytes in the readwrite zone (bump area only, excludes free list) */
76
+ get rwRemaining(): number;
77
+ /**
78
+ * Total available bytes in the readonly zone (bump + free list).
79
+ */
80
+ get roAvailable(): number;
81
+ /**
82
+ * Total available bytes in the readwrite zone (bump + free list).
83
+ */
84
+ get rwAvailable(): number;
85
+ /**
86
+ * First-fit search on a free list. Returns the index of the matching block,
87
+ * or -1 if none found.
88
+ */
89
+ private static findFreeBlock;
90
+ /**
91
+ * Allocates from a free list block. If the block is larger than needed,
92
+ * the remainder is kept in the free list.
93
+ */
94
+ private static splitFreeBlock;
95
+ /**
96
+ * Inserts a freed block into the free list (sorted by offset)
97
+ * and merges with adjacent blocks.
98
+ */
99
+ private static insertAndCoalesce;
100
+ /**
101
+ * Allocates from the readonly zone.
102
+ * Checks the free list first (first-fit), then falls back to bumping.
103
+ *
104
+ * The returned pointer is inside the romem-registered region —
105
+ * writes to it will benefit from snapshot-based skip optimization.
106
+ *
107
+ * @param size Number of bytes to allocate.
108
+ * @returns HeapAlloc with the remote pointer and size.
109
+ * @throws If the readonly zone doesn't have enough space.
110
+ */
111
+ allocReadonly(size: number): HeapAlloc;
112
+ /**
113
+ * Allocates from the readwrite zone.
114
+ * Checks the free list first (first-fit), then falls back to bumping.
115
+ *
116
+ * Standard memory — no romem tracking.
117
+ *
118
+ * @param size Number of bytes to allocate.
119
+ * @returns HeapAlloc with the remote pointer and size.
120
+ * @throws If the readwrite zone doesn't have enough space.
121
+ */
122
+ alloc(size: number): HeapAlloc;
123
+ /**
124
+ * Frees a previously allocated block, returning it to the appropriate
125
+ * zone's free list. Adjacent free blocks are automatically coalesced.
126
+ *
127
+ * Does NOT zero the remote memory. The romem snapshot for readonly
128
+ * allocations remains unchanged (will be updated on next write).
129
+ *
130
+ * @param alloc The HeapAlloc returned by alloc() or allocReadonly().
131
+ * @throws If the allocation doesn't belong to this heap.
132
+ */
133
+ free(alloc: HeapAlloc): void;
134
+ /**
135
+ * Resets both zones — clears free lists and bump pointers.
136
+ * Does NOT zero out the remote memory — call memset separately if needed.
137
+ * The romem snapshot (local buffer) is also reset to all zeroes.
138
+ */
139
+ reset(): void;
140
+ /**
141
+ * Frees the entire heap block in the target process and unregisters the romem.
142
+ *
143
+ * @param proxy The proxy thread to execute free on.
144
+ */
145
+ destroy(proxy: ProxyThread): Promise<void>;
146
+ }
147
+ //# sourceMappingURL=heap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heap.d.ts","sourceRoot":"","sources":["../../src/memory/heap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,YAAY,CAAC;AAGpB,sCAAsC;AACtC,eAAO,MAAM,iBAAiB,QAAQ,CAAC;AAEvC,0EAA0E;AAC1E,MAAM,WAAW,SAAS;IACxB,2CAA2C;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,aAAa,CAAC;IACtC,8BAA8B;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAUD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,IAAI;IACf,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,aAAa,CAAC;IACpC,6BAA6B;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,gCAAgC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iCAAiC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,6CAA6C;IAC7C,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAE/B,mDAAmD;IACnD,OAAO,CAAC,QAAQ,CAAK;IACrB,oDAAoD;IACpD,OAAO,CAAC,QAAQ,CAAK;IAErB,yDAAyD;IACzD,OAAO,CAAC,UAAU,CAAmB;IACrC,0DAA0D;IAC1D,OAAO,CAAC,UAAU,CAAmB;IAErC,OAAO;IAcP;;;;;;;;OAQG;WACU,MAAM,CACjB,KAAK,EAAE,WAAW,EAClB,SAAS,GAAE,MAA0B,EACrC,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC;IAuBhB,qDAAqD;IACrD,IAAI,MAAM,IAAI,MAAM,CAAC,aAAa,CAEjC;IAED,gFAAgF;IAChF,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,iFAAiF;IACjF,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAIxB;IAED;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAIxB;IAED;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IAO5B;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAmB7B;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAqChC;;;;;;;;;;OAUG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS;IA2BtC;;;;;;;;;OASG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS;IAyB9B;;;;;;;;;OASG;IACH,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAqB5B;;;;OAIG;IACH,KAAK,IAAI,IAAI;IAQb;;;;OAIG;IACG,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAIjD"}
@@ -0,0 +1,276 @@
1
+ import * as Native from '@cheatron/native';
2
+ import { registerReadOnlyMemory, unregisterReadOnlyMemory, } from './romem.js';
3
+ import { crt } from '../crt.js';
4
+ /** Default total heap size (bytes) */
5
+ export const DEFAULT_HEAP_SIZE = 16384;
6
+ /**
7
+ * A lightweight allocator that pre-allocates a single contiguous block
8
+ * in the target process and carves out sub-allocations from it.
9
+ *
10
+ * The block is split into two zones:
11
+ * - **Readonly zone** (first half): registered as romem — writes automatically
12
+ * skip unchanged bytes via snapshot diffing.
13
+ * - **ReadWrite zone** (second half): standard memory — no snapshot tracking.
14
+ *
15
+ * Supports `free()` — freed blocks are returned to a per-zone free list
16
+ * with automatic coalescing of adjacent blocks. New allocations check the
17
+ * free list first (first-fit), then fall back to bumping.
18
+ *
19
+ * ```
20
+ * ┌──────────────────────────────────────────┐
21
+ * │ base │
22
+ * │ ├── readonly zone (roSize bytes) │
23
+ * │ │ ├── alloc 1 │
24
+ * │ │ ├── [freed → free list] │
25
+ * │ │ ├── alloc 3 │
26
+ * │ │ └── ... (bump / reuse →) │
27
+ * │ ├── readwrite zone (rwSize bytes) │
28
+ * │ │ ├── alloc 1 │
29
+ * │ │ ├── [freed → free list] │
30
+ * │ │ └── ... (bump / reuse →) │
31
+ * └──────────────────────────────────────────┘
32
+ * ```
33
+ */
34
+ export class Heap {
35
+ /** Base remote address of the entire heap block */
36
+ base;
37
+ /** Total size of the heap */
38
+ totalSize;
39
+ /** Size of the readonly zone */
40
+ roSize;
41
+ /** Size of the readwrite zone */
42
+ rwSize;
43
+ /** The romem handle for the readonly zone */
44
+ romem;
45
+ /** Current bump offset within the readonly zone */
46
+ roOffset = 0;
47
+ /** Current bump offset within the readwrite zone */
48
+ rwOffset = 0;
49
+ /** Free list for the readonly zone (sorted by offset) */
50
+ roFreeList = [];
51
+ /** Free list for the readwrite zone (sorted by offset) */
52
+ rwFreeList = [];
53
+ constructor(base, totalSize, roSize, rwSize, romem) {
54
+ this.base = base;
55
+ this.totalSize = totalSize;
56
+ this.roSize = roSize;
57
+ this.rwSize = rwSize;
58
+ this.romem = romem;
59
+ }
60
+ /**
61
+ * Creates a new Heap by allocating a single contiguous block in the target
62
+ * process via `calloc`. The block is zero-initialized.
63
+ *
64
+ * @param proxy The proxy thread to execute calloc on.
65
+ * @param totalSize Total heap size in bytes (default: 16384).
66
+ * @param roSize Size of the readonly zone (default: half of totalSize).
67
+ * @returns A ready-to-use Heap instance.
68
+ */
69
+ static async create(proxy, totalSize = DEFAULT_HEAP_SIZE, roSize) {
70
+ const actualRoSize = roSize ?? Math.floor(totalSize / 2);
71
+ const rwSize = totalSize - actualRoSize;
72
+ if (actualRoSize < 0 || rwSize < 0) {
73
+ throw new Error(`Invalid heap sizes: roSize=${actualRoSize}, rwSize=${rwSize}`);
74
+ }
75
+ const base = await proxy.call(crt.calloc, 1, totalSize);
76
+ if (base.address === 0n) {
77
+ throw new Error(`calloc(1, ${totalSize}) returned NULL`);
78
+ }
79
+ // Register the readonly zone as romem for snapshot-based write optimization
80
+ const roRemote = base;
81
+ const roLocal = Buffer.alloc(actualRoSize); // zero-filled — matches calloc
82
+ const romem = registerReadOnlyMemory(roRemote, roLocal);
83
+ return new Heap(base, totalSize, actualRoSize, rwSize, romem);
84
+ }
85
+ /** Remote address where the readwrite zone starts */
86
+ get rwBase() {
87
+ return new Native.NativePointer(this.base.address + BigInt(this.roSize));
88
+ }
89
+ /** Remaining bytes in the readonly zone (bump area only, excludes free list) */
90
+ get roRemaining() {
91
+ return this.roSize - this.roOffset;
92
+ }
93
+ /** Remaining bytes in the readwrite zone (bump area only, excludes free list) */
94
+ get rwRemaining() {
95
+ return this.rwSize - this.rwOffset;
96
+ }
97
+ /**
98
+ * Total available bytes in the readonly zone (bump + free list).
99
+ */
100
+ get roAvailable() {
101
+ return (this.roRemaining + this.roFreeList.reduce((sum, b) => sum + b.size, 0));
102
+ }
103
+ /**
104
+ * Total available bytes in the readwrite zone (bump + free list).
105
+ */
106
+ get rwAvailable() {
107
+ return (this.rwRemaining + this.rwFreeList.reduce((sum, b) => sum + b.size, 0));
108
+ }
109
+ /**
110
+ * First-fit search on a free list. Returns the index of the matching block,
111
+ * or -1 if none found.
112
+ */
113
+ static findFreeBlock(freeList, size) {
114
+ for (let i = 0; i < freeList.length; i++) {
115
+ if (freeList[i].size >= size)
116
+ return i;
117
+ }
118
+ return -1;
119
+ }
120
+ /**
121
+ * Allocates from a free list block. If the block is larger than needed,
122
+ * the remainder is kept in the free list.
123
+ */
124
+ static splitFreeBlock(freeList, index, size) {
125
+ const block = freeList[index];
126
+ const offset = block.offset;
127
+ const remainder = block.size - size;
128
+ if (remainder > 0) {
129
+ block.offset += size;
130
+ block.size = remainder;
131
+ }
132
+ else {
133
+ freeList.splice(index, 1);
134
+ }
135
+ return offset;
136
+ }
137
+ /**
138
+ * Inserts a freed block into the free list (sorted by offset)
139
+ * and merges with adjacent blocks.
140
+ */
141
+ static insertAndCoalesce(freeList, offset, size) {
142
+ // Find insertion point (keep sorted by offset)
143
+ let insertIdx = 0;
144
+ while (insertIdx < freeList.length &&
145
+ freeList[insertIdx].offset < offset) {
146
+ insertIdx++;
147
+ }
148
+ freeList.splice(insertIdx, 0, { offset, size });
149
+ // Merge with next block
150
+ if (insertIdx + 1 < freeList.length) {
151
+ const curr = freeList[insertIdx];
152
+ const next = freeList[insertIdx + 1];
153
+ if (curr.offset + curr.size === next.offset) {
154
+ curr.size += next.size;
155
+ freeList.splice(insertIdx + 1, 1);
156
+ }
157
+ }
158
+ // Merge with previous block
159
+ if (insertIdx > 0) {
160
+ const prev = freeList[insertIdx - 1];
161
+ const curr = freeList[insertIdx];
162
+ if (prev.offset + prev.size === curr.offset) {
163
+ prev.size += curr.size;
164
+ freeList.splice(insertIdx, 1);
165
+ }
166
+ }
167
+ }
168
+ /**
169
+ * Allocates from the readonly zone.
170
+ * Checks the free list first (first-fit), then falls back to bumping.
171
+ *
172
+ * The returned pointer is inside the romem-registered region —
173
+ * writes to it will benefit from snapshot-based skip optimization.
174
+ *
175
+ * @param size Number of bytes to allocate.
176
+ * @returns HeapAlloc with the remote pointer and size.
177
+ * @throws If the readonly zone doesn't have enough space.
178
+ */
179
+ allocReadonly(size) {
180
+ if (size <= 0)
181
+ throw new Error(`Invalid alloc size: ${size}`);
182
+ // Try free list first
183
+ const freeIdx = Heap.findFreeBlock(this.roFreeList, size);
184
+ if (freeIdx !== -1) {
185
+ const offset = Heap.splitFreeBlock(this.roFreeList, freeIdx, size);
186
+ const remote = new Native.NativePointer(this.base.address + BigInt(offset));
187
+ return { remote, size };
188
+ }
189
+ // Bump allocate
190
+ if (this.roOffset + size > this.roSize) {
191
+ throw new Error(`Readonly zone exhausted: requested ${size}, available ${this.roAvailable}`);
192
+ }
193
+ const remote = new Native.NativePointer(this.base.address + BigInt(this.roOffset));
194
+ this.roOffset += size;
195
+ return { remote, size };
196
+ }
197
+ /**
198
+ * Allocates from the readwrite zone.
199
+ * Checks the free list first (first-fit), then falls back to bumping.
200
+ *
201
+ * Standard memory — no romem tracking.
202
+ *
203
+ * @param size Number of bytes to allocate.
204
+ * @returns HeapAlloc with the remote pointer and size.
205
+ * @throws If the readwrite zone doesn't have enough space.
206
+ */
207
+ alloc(size) {
208
+ if (size <= 0)
209
+ throw new Error(`Invalid alloc size: ${size}`);
210
+ // Try free list first
211
+ const freeIdx = Heap.findFreeBlock(this.rwFreeList, size);
212
+ if (freeIdx !== -1) {
213
+ const offset = Heap.splitFreeBlock(this.rwFreeList, freeIdx, size);
214
+ const remote = new Native.NativePointer(this.base.address + BigInt(this.roSize) + BigInt(offset));
215
+ return { remote, size };
216
+ }
217
+ // Bump allocate
218
+ if (this.rwOffset + size > this.rwSize) {
219
+ throw new Error(`ReadWrite zone exhausted: requested ${size}, available ${this.rwAvailable}`);
220
+ }
221
+ const remote = this.base.add(BigInt(this.roSize) + BigInt(this.rwOffset));
222
+ this.rwOffset += size;
223
+ return { remote, size };
224
+ }
225
+ /**
226
+ * Frees a previously allocated block, returning it to the appropriate
227
+ * zone's free list. Adjacent free blocks are automatically coalesced.
228
+ *
229
+ * Does NOT zero the remote memory. The romem snapshot for readonly
230
+ * allocations remains unchanged (will be updated on next write).
231
+ *
232
+ * @param alloc The HeapAlloc returned by alloc() or allocReadonly().
233
+ * @throws If the allocation doesn't belong to this heap.
234
+ */
235
+ free(alloc) {
236
+ const addr = alloc.remote.address;
237
+ const baseAddr = this.base.address;
238
+ const roEnd = baseAddr + BigInt(this.roSize);
239
+ const rwEnd = roEnd + BigInt(this.rwSize);
240
+ if (addr >= baseAddr && addr < roEnd) {
241
+ // Readonly zone
242
+ const offset = Number(addr - baseAddr);
243
+ Heap.insertAndCoalesce(this.roFreeList, offset, alloc.size);
244
+ }
245
+ else if (addr >= roEnd && addr < rwEnd) {
246
+ // ReadWrite zone — offset relative to rw zone start
247
+ const offset = Number(addr - roEnd);
248
+ Heap.insertAndCoalesce(this.rwFreeList, offset, alloc.size);
249
+ }
250
+ else {
251
+ throw new Error(`Address 0x${addr.toString(16)} does not belong to this heap`);
252
+ }
253
+ }
254
+ /**
255
+ * Resets both zones — clears free lists and bump pointers.
256
+ * Does NOT zero out the remote memory — call memset separately if needed.
257
+ * The romem snapshot (local buffer) is also reset to all zeroes.
258
+ */
259
+ reset() {
260
+ this.roOffset = 0;
261
+ this.rwOffset = 0;
262
+ this.roFreeList.length = 0;
263
+ this.rwFreeList.length = 0;
264
+ this.romem.local.fill(0);
265
+ }
266
+ /**
267
+ * Frees the entire heap block in the target process and unregisters the romem.
268
+ *
269
+ * @param proxy The proxy thread to execute free on.
270
+ */
271
+ async destroy(proxy) {
272
+ unregisterReadOnlyMemory(this.romem);
273
+ await proxy.call(crt.free, this.base);
274
+ }
275
+ }
276
+ //# sourceMappingURL=heap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heap.js","sourceRoot":"","sources":["../../src/memory/heap.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import * as Native from '@cheatron/native';
2
+ import type { ProxyThread } from '../thread/proxy-thread.js';
3
+ /**
4
+ * A read-only memory region allocated in the target process.
5
+ * Stores both the remote pointer and a local Buffer copy.
6
+ * Since we are the ones who wrote it, we always know the exact contents —
7
+ * this lets writeMemory skip unchanged bytes automatically.
8
+ */
9
+ export interface ReadOnlyMemory {
10
+ /** Remote address in the target process (allocated via calloc) */
11
+ readonly remote: Native.NativePointer;
12
+ /** Local copy of the data — always mirrors what is on the remote side */
13
+ readonly local: Buffer;
14
+ }
15
+ /**
16
+ * Allocates a zero-initialized read-only memory region in the target process
17
+ * via hijacked `calloc(1, size)` and registers it for write-optimization.
18
+ *
19
+ * @param proxy The proxy thread to execute calloc on.
20
+ * @param size Total byte size to allocate.
21
+ * @returns A ReadOnlyMemory handle.
22
+ */
23
+ export declare function createReadOnlyMemory(proxy: ProxyThread, size: number): Promise<ReadOnlyMemory>;
24
+ /**
25
+ * Registers an existing pointer + buffer pair as a read-only memory region.
26
+ * Use this when the memory was allocated through other means but you still
27
+ * want writeMemory to benefit from the snapshot optimization.
28
+ *
29
+ * @param remote Address in the target process.
30
+ * @param local Buffer that mirrors the remote contents exactly.
31
+ */
32
+ export declare function registerReadOnlyMemory(remote: Native.NativePointer, local: Buffer): ReadOnlyMemory;
33
+ /**
34
+ * Removes a read-only memory region from the registry.
35
+ * Does NOT free the remote allocation — call `free` separately if needed.
36
+ */
37
+ export declare function unregisterReadOnlyMemory(romem: ReadOnlyMemory): boolean;
38
+ /**
39
+ * Checks whether a write range [destAddr, destAddr + writeLen) overlaps
40
+ * with any registered read-only region.
41
+ *
42
+ * Returns the overlapping region, or undefined if no overlap.
43
+ */
44
+ export declare function findOverlappingRegion(destAddr: bigint, writeLen: number): ReadOnlyMemory | undefined;
45
+ /**
46
+ * Extracts the local snapshot bytes for the overlapping portion of a write.
47
+ *
48
+ * Given a write to [destAddr, destAddr + writeLen) that overlaps with `romem`,
49
+ * returns the Buffer slice from romem.local that corresponds to the overlap region,
50
+ * along with the overlap boundaries relative to the write.
51
+ */
52
+ export declare function getOverlapInfo(destAddr: bigint, writeLen: number, romem: ReadOnlyMemory): {
53
+ /** Offset within the write buffer where the overlap begins */
54
+ writeOffset: number;
55
+ /** Length of the overlapping region */
56
+ overlapLen: number;
57
+ /** The snapshot bytes from romem.local for the overlapping range */
58
+ snapshot: Buffer;
59
+ };
60
+ /**
61
+ * Updates the local snapshot of a read-only region after a successful write.
62
+ * Call this after writeMemorySafeBuffer completes to keep the snapshot current.
63
+ *
64
+ * @param romem The read-only memory region.
65
+ * @param source The data that was written.
66
+ * @param destAddr The remote address that was written to.
67
+ */
68
+ export declare function updateSnapshot(romem: ReadOnlyMemory, source: Buffer, destAddr: bigint): void;
69
+ //# sourceMappingURL=romem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"romem.d.ts","sourceRoot":"","sources":["../../src/memory/romem.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAG7D;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,aAAa,CAAC;IACtC,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAKD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,cAAc,CAAC,CAUzB;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,CAAC,aAAa,EAC5B,KAAK,EAAE,MAAM,GACZ,cAAc,CAIhB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAKvE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,cAAc,GAAG,SAAS,CAW5B;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,cAAc,GACpB;IACD,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;CAClB,CAiBA;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,cAAc,EACrB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,IAAI,CAeN"}
@@ -0,0 +1,108 @@
1
+ import * as Native from '@cheatron/native';
2
+ import { crt } from '../crt.js';
3
+ /** Internal storage for all registered read-only regions */
4
+ const regions = [];
5
+ /**
6
+ * Allocates a zero-initialized read-only memory region in the target process
7
+ * via hijacked `calloc(1, size)` and registers it for write-optimization.
8
+ *
9
+ * @param proxy The proxy thread to execute calloc on.
10
+ * @param size Total byte size to allocate.
11
+ * @returns A ReadOnlyMemory handle.
12
+ */
13
+ export async function createReadOnlyMemory(proxy, size) {
14
+ const ptr = await proxy.call(crt.calloc, 1, size);
15
+ if (ptr.address === 0n) {
16
+ throw new Error(`calloc(1, ${size}) returned NULL`);
17
+ }
18
+ const local = Buffer.alloc(size); // zero-filled — matches calloc
19
+ const romem = { remote: ptr, local };
20
+ regions.push(romem);
21
+ return romem;
22
+ }
23
+ /**
24
+ * Registers an existing pointer + buffer pair as a read-only memory region.
25
+ * Use this when the memory was allocated through other means but you still
26
+ * want writeMemory to benefit from the snapshot optimization.
27
+ *
28
+ * @param remote Address in the target process.
29
+ * @param local Buffer that mirrors the remote contents exactly.
30
+ */
31
+ export function registerReadOnlyMemory(remote, local) {
32
+ const romem = { remote, local };
33
+ regions.push(romem);
34
+ return romem;
35
+ }
36
+ /**
37
+ * Removes a read-only memory region from the registry.
38
+ * Does NOT free the remote allocation — call `free` separately if needed.
39
+ */
40
+ export function unregisterReadOnlyMemory(romem) {
41
+ const idx = regions.indexOf(romem);
42
+ if (idx === -1)
43
+ return false;
44
+ regions.splice(idx, 1);
45
+ return true;
46
+ }
47
+ /**
48
+ * Checks whether a write range [destAddr, destAddr + writeLen) overlaps
49
+ * with any registered read-only region.
50
+ *
51
+ * Returns the overlapping region, or undefined if no overlap.
52
+ */
53
+ export function findOverlappingRegion(destAddr, writeLen) {
54
+ const writeEnd = destAddr + BigInt(writeLen);
55
+ for (const r of regions) {
56
+ const rStart = r.remote.address;
57
+ const rEnd = rStart + BigInt(r.local.length);
58
+ // overlap: !(writeEnd <= rStart || destAddr >= rEnd)
59
+ if (writeEnd > rStart && destAddr < rEnd) {
60
+ return r;
61
+ }
62
+ }
63
+ return undefined;
64
+ }
65
+ /**
66
+ * Extracts the local snapshot bytes for the overlapping portion of a write.
67
+ *
68
+ * Given a write to [destAddr, destAddr + writeLen) that overlaps with `romem`,
69
+ * returns the Buffer slice from romem.local that corresponds to the overlap region,
70
+ * along with the overlap boundaries relative to the write.
71
+ */
72
+ export function getOverlapInfo(destAddr, writeLen, romem) {
73
+ const writeEnd = destAddr + BigInt(writeLen);
74
+ const rStart = romem.remote.address;
75
+ const rEnd = rStart + BigInt(romem.local.length);
76
+ const overlapStart = destAddr > rStart ? destAddr : rStart;
77
+ const overlapEnd = writeEnd < rEnd ? writeEnd : rEnd;
78
+ const overlapLen = Number(overlapEnd - overlapStart);
79
+ // Offset within the write buffer
80
+ const writeOffset = Number(overlapStart - destAddr);
81
+ // Offset within romem.local
82
+ const romemOffset = Number(overlapStart - rStart);
83
+ const snapshot = romem.local.subarray(romemOffset, romemOffset + overlapLen);
84
+ return { writeOffset, overlapLen, snapshot };
85
+ }
86
+ /**
87
+ * Updates the local snapshot of a read-only region after a successful write.
88
+ * Call this after writeMemorySafeBuffer completes to keep the snapshot current.
89
+ *
90
+ * @param romem The read-only memory region.
91
+ * @param source The data that was written.
92
+ * @param destAddr The remote address that was written to.
93
+ */
94
+ export function updateSnapshot(romem, source, destAddr) {
95
+ const rStart = romem.remote.address;
96
+ const writeStart = destAddr;
97
+ const writeEnd = writeStart + BigInt(source.length);
98
+ const rEnd = rStart + BigInt(romem.local.length);
99
+ const overlapStart = writeStart > rStart ? writeStart : rStart;
100
+ const overlapEnd = writeEnd < rEnd ? writeEnd : rEnd;
101
+ if (overlapEnd <= overlapStart)
102
+ return;
103
+ const srcOffset = Number(overlapStart - writeStart);
104
+ const dstOffset = Number(overlapStart - rStart);
105
+ const len = Number(overlapEnd - overlapStart);
106
+ source.copy(romem.local, dstOffset, srcOffset, srcOffset + len);
107
+ }
108
+ //# sourceMappingURL=romem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"romem.js","sourceRoot":"","sources":["../../src/memory/romem.ts"],"names":[],"mappings":"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"}