mustardscript 0.1.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 (99) hide show
  1. package/Cargo.lock +1579 -0
  2. package/Cargo.toml +40 -0
  3. package/LICENSE +201 -0
  4. package/README.md +828 -0
  5. package/SECURITY.md +34 -0
  6. package/crates/mustard/Cargo.toml +31 -0
  7. package/crates/mustard/src/cancellation.rs +28 -0
  8. package/crates/mustard/src/diagnostic.rs +145 -0
  9. package/crates/mustard/src/ir.rs +435 -0
  10. package/crates/mustard/src/lib.rs +21 -0
  11. package/crates/mustard/src/limits.rs +22 -0
  12. package/crates/mustard/src/parser/expressions.rs +723 -0
  13. package/crates/mustard/src/parser/mod.rs +115 -0
  14. package/crates/mustard/src/parser/operators.rs +105 -0
  15. package/crates/mustard/src/parser/patterns.rs +123 -0
  16. package/crates/mustard/src/parser/scope.rs +107 -0
  17. package/crates/mustard/src/parser/statements.rs +298 -0
  18. package/crates/mustard/src/parser/tests/acceptance.rs +339 -0
  19. package/crates/mustard/src/parser/tests/mod.rs +2 -0
  20. package/crates/mustard/src/parser/tests/rejections.rs +107 -0
  21. package/crates/mustard/src/runtime/accounting.rs +613 -0
  22. package/crates/mustard/src/runtime/api.rs +192 -0
  23. package/crates/mustard/src/runtime/async_runtime/mod.rs +5 -0
  24. package/crates/mustard/src/runtime/async_runtime/promises.rs +246 -0
  25. package/crates/mustard/src/runtime/async_runtime/reactions.rs +400 -0
  26. package/crates/mustard/src/runtime/async_runtime/scheduler.rs +224 -0
  27. package/crates/mustard/src/runtime/builtins/arrays.rs +1205 -0
  28. package/crates/mustard/src/runtime/builtins/collections.rs +573 -0
  29. package/crates/mustard/src/runtime/builtins/install.rs +501 -0
  30. package/crates/mustard/src/runtime/builtins/intl.rs +553 -0
  31. package/crates/mustard/src/runtime/builtins/mod.rs +25 -0
  32. package/crates/mustard/src/runtime/builtins/objects.rs +405 -0
  33. package/crates/mustard/src/runtime/builtins/primitives.rs +859 -0
  34. package/crates/mustard/src/runtime/builtins/promises.rs +335 -0
  35. package/crates/mustard/src/runtime/builtins/regexp.rs +356 -0
  36. package/crates/mustard/src/runtime/builtins/strings.rs +803 -0
  37. package/crates/mustard/src/runtime/builtins/support.rs +561 -0
  38. package/crates/mustard/src/runtime/bytecode.rs +123 -0
  39. package/crates/mustard/src/runtime/compiler/assignments.rs +690 -0
  40. package/crates/mustard/src/runtime/compiler/bindings.rs +92 -0
  41. package/crates/mustard/src/runtime/compiler/context.rs +46 -0
  42. package/crates/mustard/src/runtime/compiler/control.rs +342 -0
  43. package/crates/mustard/src/runtime/compiler/expressions.rs +372 -0
  44. package/crates/mustard/src/runtime/compiler/mod.rs +173 -0
  45. package/crates/mustard/src/runtime/compiler/statements.rs +459 -0
  46. package/crates/mustard/src/runtime/conversions/boundary.rs +293 -0
  47. package/crates/mustard/src/runtime/conversions/coercions.rs +217 -0
  48. package/crates/mustard/src/runtime/conversions/errors.rs +118 -0
  49. package/crates/mustard/src/runtime/conversions/mod.rs +14 -0
  50. package/crates/mustard/src/runtime/conversions/operators.rs +334 -0
  51. package/crates/mustard/src/runtime/env.rs +355 -0
  52. package/crates/mustard/src/runtime/exceptions.rs +377 -0
  53. package/crates/mustard/src/runtime/gc.rs +595 -0
  54. package/crates/mustard/src/runtime/mod.rs +318 -0
  55. package/crates/mustard/src/runtime/properties.rs +1762 -0
  56. package/crates/mustard/src/runtime/serialization.rs +127 -0
  57. package/crates/mustard/src/runtime/shared.rs +108 -0
  58. package/crates/mustard/src/runtime/snapshot_validation_tests.rs +93 -0
  59. package/crates/mustard/src/runtime/state.rs +652 -0
  60. package/crates/mustard/src/runtime/tests/async_host.rs +104 -0
  61. package/crates/mustard/src/runtime/tests/collections.rs +50 -0
  62. package/crates/mustard/src/runtime/tests/diagnostics.rs +36 -0
  63. package/crates/mustard/src/runtime/tests/exceptions.rs +122 -0
  64. package/crates/mustard/src/runtime/tests/execution.rs +553 -0
  65. package/crates/mustard/src/runtime/tests/gc.rs +533 -0
  66. package/crates/mustard/src/runtime/tests/mod.rs +56 -0
  67. package/crates/mustard/src/runtime/tests/serialization.rs +170 -0
  68. package/crates/mustard/src/runtime/validation/bytecode.rs +484 -0
  69. package/crates/mustard/src/runtime/validation/mod.rs +14 -0
  70. package/crates/mustard/src/runtime/validation/policy.rs +94 -0
  71. package/crates/mustard/src/runtime/validation/snapshot.rs +406 -0
  72. package/crates/mustard/src/runtime/validation/walk.rs +206 -0
  73. package/crates/mustard/src/runtime/vm.rs +1016 -0
  74. package/crates/mustard/src/span.rs +22 -0
  75. package/crates/mustard/src/structured.rs +107 -0
  76. package/crates/mustard-bridge/Cargo.toml +17 -0
  77. package/crates/mustard-bridge/src/codec.rs +46 -0
  78. package/crates/mustard-bridge/src/dto.rs +99 -0
  79. package/crates/mustard-bridge/src/lib.rs +12 -0
  80. package/crates/mustard-bridge/src/operations.rs +142 -0
  81. package/crates/mustard-node/Cargo.toml +24 -0
  82. package/crates/mustard-node/build.rs +3 -0
  83. package/crates/mustard-node/src/lib.rs +236 -0
  84. package/crates/mustard-sidecar/Cargo.toml +21 -0
  85. package/crates/mustard-sidecar/src/lib.rs +134 -0
  86. package/crates/mustard-sidecar/src/main.rs +36 -0
  87. package/dist/index.js +20 -0
  88. package/dist/install.js +117 -0
  89. package/dist/lib/cancellation.js +124 -0
  90. package/dist/lib/errors.js +46 -0
  91. package/dist/lib/executor.js +555 -0
  92. package/dist/lib/policy.js +292 -0
  93. package/dist/lib/progress.js +356 -0
  94. package/dist/lib/runtime.js +109 -0
  95. package/dist/lib/structured.js +286 -0
  96. package/dist/native-loader.js +227 -0
  97. package/index.d.ts +23 -0
  98. package/mustard.d.ts +220 -0
  99. package/package.json +97 -0
@@ -0,0 +1,613 @@
1
+ use super::*;
2
+
3
+ impl Runtime {
4
+ pub(super) fn ensure_heap_capacity(&self, additional_bytes: usize) -> MustardResult<()> {
5
+ let next = self
6
+ .heap_bytes_used
7
+ .checked_add(additional_bytes)
8
+ .ok_or_else(|| limit_error("heap limit exceeded"))?;
9
+ if next > self.limits.heap_limit_bytes {
10
+ return Err(limit_error("heap limit exceeded"));
11
+ }
12
+ Ok(())
13
+ }
14
+
15
+ pub(super) fn account_new_allocation(&mut self, bytes: usize) -> MustardResult<()> {
16
+ let next_allocations = self
17
+ .allocation_count
18
+ .checked_add(1)
19
+ .ok_or_else(|| limit_error("allocation budget exhausted"))?;
20
+ if next_allocations > self.limits.allocation_budget {
21
+ return Err(limit_error("allocation budget exhausted"));
22
+ }
23
+ self.ensure_heap_capacity(bytes)?;
24
+ self.allocation_count = next_allocations;
25
+ self.heap_bytes_used += bytes;
26
+ Ok(())
27
+ }
28
+
29
+ pub(super) fn apply_heap_delta(
30
+ &mut self,
31
+ old_bytes: usize,
32
+ new_bytes: usize,
33
+ ) -> MustardResult<()> {
34
+ if new_bytes >= old_bytes {
35
+ self.ensure_heap_capacity(new_bytes - old_bytes)?;
36
+ self.heap_bytes_used += new_bytes - old_bytes;
37
+ } else {
38
+ self.heap_bytes_used -= old_bytes - new_bytes;
39
+ }
40
+ Ok(())
41
+ }
42
+
43
+ pub(super) fn insert_env(&mut self, parent: Option<EnvKey>) -> MustardResult<EnvKey> {
44
+ let mut env = Env {
45
+ parent,
46
+ bindings: IndexMap::new(),
47
+ accounted_bytes: 0,
48
+ };
49
+ env.accounted_bytes = measure_env_bytes(&env);
50
+ self.account_new_allocation(env.accounted_bytes)?;
51
+ Ok(self.envs.insert(env))
52
+ }
53
+
54
+ pub(super) fn insert_cell(
55
+ &mut self,
56
+ value: Value,
57
+ mutable: bool,
58
+ initialized: bool,
59
+ ) -> MustardResult<CellKey> {
60
+ let mut cell = Cell {
61
+ value,
62
+ mutable,
63
+ initialized,
64
+ accounted_bytes: 0,
65
+ };
66
+ cell.accounted_bytes = measure_cell_bytes(&cell);
67
+ self.account_new_allocation(cell.accounted_bytes)?;
68
+ Ok(self.cells.insert(cell))
69
+ }
70
+
71
+ pub(super) fn insert_object(
72
+ &mut self,
73
+ properties: IndexMap<String, Value>,
74
+ kind: ObjectKind,
75
+ ) -> MustardResult<ObjectKey> {
76
+ let mut object = PlainObject {
77
+ properties,
78
+ kind,
79
+ accounted_bytes: 0,
80
+ };
81
+ object.accounted_bytes = measure_object_bytes(&object);
82
+ self.account_new_allocation(object.accounted_bytes)?;
83
+ Ok(self.objects.insert(object))
84
+ }
85
+
86
+ pub(super) fn insert_array(
87
+ &mut self,
88
+ elements: Vec<Value>,
89
+ properties: IndexMap<String, Value>,
90
+ ) -> MustardResult<ArrayKey> {
91
+ self.insert_sparse_array(elements.into_iter().map(Some).collect(), properties)
92
+ }
93
+
94
+ pub(super) fn insert_sparse_array(
95
+ &mut self,
96
+ elements: Vec<Option<Value>>,
97
+ properties: IndexMap<String, Value>,
98
+ ) -> MustardResult<ArrayKey> {
99
+ let mut array = ArrayObject {
100
+ elements,
101
+ properties,
102
+ accounted_bytes: 0,
103
+ };
104
+ array.accounted_bytes = measure_array_bytes(&array);
105
+ self.account_new_allocation(array.accounted_bytes)?;
106
+ Ok(self.arrays.insert(array))
107
+ }
108
+
109
+ pub(super) fn insert_map(&mut self, entries: Vec<MapEntry>) -> MustardResult<MapKey> {
110
+ let mut map = MapObject {
111
+ entries,
112
+ accounted_bytes: 0,
113
+ };
114
+ map.accounted_bytes = measure_map_bytes(&map);
115
+ self.account_new_allocation(map.accounted_bytes)?;
116
+ Ok(self.maps.insert(map))
117
+ }
118
+
119
+ pub(super) fn insert_set(&mut self, entries: Vec<Value>) -> MustardResult<SetKey> {
120
+ let mut set = SetObject {
121
+ entries,
122
+ accounted_bytes: 0,
123
+ };
124
+ set.accounted_bytes = measure_set_bytes(&set);
125
+ self.account_new_allocation(set.accounted_bytes)?;
126
+ Ok(self.sets.insert(set))
127
+ }
128
+
129
+ pub(super) fn insert_iterator(&mut self, state: IteratorState) -> MustardResult<IteratorKey> {
130
+ let mut iterator = IteratorObject {
131
+ state,
132
+ accounted_bytes: 0,
133
+ };
134
+ iterator.accounted_bytes = measure_iterator_bytes(&iterator);
135
+ self.account_new_allocation(iterator.accounted_bytes)?;
136
+ Ok(self.iterators.insert(iterator))
137
+ }
138
+
139
+ pub(super) fn insert_closure(
140
+ &mut self,
141
+ function_id: usize,
142
+ env: EnvKey,
143
+ this_value: Value,
144
+ ) -> MustardResult<ClosureKey> {
145
+ let mut closure = Closure {
146
+ function_id,
147
+ env,
148
+ name: self
149
+ .program
150
+ .functions
151
+ .get(function_id)
152
+ .and_then(|function| function.name.clone()),
153
+ this_value,
154
+ prototype: None,
155
+ properties: IndexMap::new(),
156
+ accounted_bytes: 0,
157
+ };
158
+ closure.accounted_bytes = measure_closure_bytes(&closure);
159
+ self.account_new_allocation(closure.accounted_bytes)?;
160
+ let key = self.closures.insert(closure);
161
+ let is_arrow = self
162
+ .program
163
+ .functions
164
+ .get(function_id)
165
+ .map(|function| function.is_arrow)
166
+ .ok_or_else(|| MustardError::runtime("function not found"))?;
167
+ if !is_arrow {
168
+ let prototype = self.insert_object(
169
+ IndexMap::new(),
170
+ ObjectKind::FunctionPrototype(Value::Closure(key)),
171
+ )?;
172
+ self.closures
173
+ .get_mut(key)
174
+ .ok_or_else(|| MustardError::runtime("closure missing"))?
175
+ .prototype = Some(prototype);
176
+ self.refresh_closure_accounting(key)?;
177
+ }
178
+ Ok(key)
179
+ }
180
+
181
+ pub(super) fn insert_promise(&mut self, state: PromiseState) -> MustardResult<PromiseKey> {
182
+ let mut promise = PromiseObject {
183
+ state,
184
+ awaiters: Vec::new(),
185
+ dependents: Vec::new(),
186
+ reactions: Vec::new(),
187
+ driver: None,
188
+ accounted_bytes: 0,
189
+ };
190
+ promise.accounted_bytes = measure_promise_bytes(&promise);
191
+ self.account_new_allocation(promise.accounted_bytes)?;
192
+ Ok(self.promises.insert(promise))
193
+ }
194
+
195
+ pub(super) fn account_existing_env(&mut self, key: EnvKey) -> MustardResult<()> {
196
+ let bytes = {
197
+ let env = self
198
+ .envs
199
+ .get(key)
200
+ .ok_or_else(|| MustardError::runtime("environment missing"))?;
201
+ measure_env_bytes(env)
202
+ };
203
+ self.account_new_allocation(bytes)?;
204
+ self.envs
205
+ .get_mut(key)
206
+ .ok_or_else(|| MustardError::runtime("environment missing"))?
207
+ .accounted_bytes = bytes;
208
+ Ok(())
209
+ }
210
+
211
+ pub(super) fn refresh_env_accounting(&mut self, key: EnvKey) -> MustardResult<()> {
212
+ let (old_bytes, new_bytes) = {
213
+ let env = self
214
+ .envs
215
+ .get(key)
216
+ .ok_or_else(|| MustardError::runtime("environment missing"))?;
217
+ (env.accounted_bytes, measure_env_bytes(env))
218
+ };
219
+ self.apply_heap_delta(old_bytes, new_bytes)?;
220
+ self.envs
221
+ .get_mut(key)
222
+ .ok_or_else(|| MustardError::runtime("environment missing"))?
223
+ .accounted_bytes = new_bytes;
224
+ Ok(())
225
+ }
226
+
227
+ pub(super) fn refresh_cell_accounting(&mut self, key: CellKey) -> MustardResult<()> {
228
+ let (old_bytes, new_bytes) = {
229
+ let cell = self
230
+ .cells
231
+ .get(key)
232
+ .ok_or_else(|| MustardError::runtime("binding cell missing"))?;
233
+ (cell.accounted_bytes, measure_cell_bytes(cell))
234
+ };
235
+ self.apply_heap_delta(old_bytes, new_bytes)?;
236
+ self.cells
237
+ .get_mut(key)
238
+ .ok_or_else(|| MustardError::runtime("binding cell missing"))?
239
+ .accounted_bytes = new_bytes;
240
+ Ok(())
241
+ }
242
+
243
+ pub(super) fn refresh_object_accounting(&mut self, key: ObjectKey) -> MustardResult<()> {
244
+ let (old_bytes, new_bytes) = {
245
+ let object = self
246
+ .objects
247
+ .get(key)
248
+ .ok_or_else(|| MustardError::runtime("object missing"))?;
249
+ (object.accounted_bytes, measure_object_bytes(object))
250
+ };
251
+ self.apply_heap_delta(old_bytes, new_bytes)?;
252
+ self.objects
253
+ .get_mut(key)
254
+ .ok_or_else(|| MustardError::runtime("object missing"))?
255
+ .accounted_bytes = new_bytes;
256
+ Ok(())
257
+ }
258
+
259
+ pub(super) fn refresh_array_accounting(&mut self, key: ArrayKey) -> MustardResult<()> {
260
+ let (old_bytes, new_bytes) = {
261
+ let array = self
262
+ .arrays
263
+ .get(key)
264
+ .ok_or_else(|| MustardError::runtime("array missing"))?;
265
+ (array.accounted_bytes, measure_array_bytes(array))
266
+ };
267
+ self.apply_heap_delta(old_bytes, new_bytes)?;
268
+ self.arrays
269
+ .get_mut(key)
270
+ .ok_or_else(|| MustardError::runtime("array missing"))?
271
+ .accounted_bytes = new_bytes;
272
+ Ok(())
273
+ }
274
+
275
+ pub(super) fn refresh_map_accounting(&mut self, key: MapKey) -> MustardResult<()> {
276
+ let (old_bytes, new_bytes) = {
277
+ let map = self
278
+ .maps
279
+ .get(key)
280
+ .ok_or_else(|| MustardError::runtime("map missing"))?;
281
+ (map.accounted_bytes, measure_map_bytes(map))
282
+ };
283
+ self.apply_heap_delta(old_bytes, new_bytes)?;
284
+ self.maps
285
+ .get_mut(key)
286
+ .ok_or_else(|| MustardError::runtime("map missing"))?
287
+ .accounted_bytes = new_bytes;
288
+ Ok(())
289
+ }
290
+
291
+ pub(super) fn refresh_set_accounting(&mut self, key: SetKey) -> MustardResult<()> {
292
+ let (old_bytes, new_bytes) = {
293
+ let set = self
294
+ .sets
295
+ .get(key)
296
+ .ok_or_else(|| MustardError::runtime("set missing"))?;
297
+ (set.accounted_bytes, measure_set_bytes(set))
298
+ };
299
+ self.apply_heap_delta(old_bytes, new_bytes)?;
300
+ self.sets
301
+ .get_mut(key)
302
+ .ok_or_else(|| MustardError::runtime("set missing"))?
303
+ .accounted_bytes = new_bytes;
304
+ Ok(())
305
+ }
306
+
307
+ pub(super) fn refresh_iterator_accounting(&mut self, key: IteratorKey) -> MustardResult<()> {
308
+ let (old_bytes, new_bytes) = {
309
+ let iterator = self
310
+ .iterators
311
+ .get(key)
312
+ .ok_or_else(|| MustardError::runtime("iterator missing"))?;
313
+ (iterator.accounted_bytes, measure_iterator_bytes(iterator))
314
+ };
315
+ self.apply_heap_delta(old_bytes, new_bytes)?;
316
+ self.iterators
317
+ .get_mut(key)
318
+ .ok_or_else(|| MustardError::runtime("iterator missing"))?
319
+ .accounted_bytes = new_bytes;
320
+ Ok(())
321
+ }
322
+
323
+ pub(super) fn refresh_closure_accounting(&mut self, key: ClosureKey) -> MustardResult<()> {
324
+ let (old_bytes, new_bytes) = {
325
+ let closure = self
326
+ .closures
327
+ .get(key)
328
+ .ok_or_else(|| MustardError::runtime("closure missing"))?;
329
+ (closure.accounted_bytes, measure_closure_bytes(closure))
330
+ };
331
+ self.apply_heap_delta(old_bytes, new_bytes)?;
332
+ self.closures
333
+ .get_mut(key)
334
+ .ok_or_else(|| MustardError::runtime("closure missing"))?
335
+ .accounted_bytes = new_bytes;
336
+ Ok(())
337
+ }
338
+
339
+ pub(super) fn recompute_accounting_after_load(&mut self) -> MustardResult<()> {
340
+ let (heap_bytes_used, allocation_count) =
341
+ self.recompute_accounting_totals().map_err(|message| {
342
+ serialization_error(format!("snapshot validation failed: {message}"))
343
+ })?;
344
+
345
+ if heap_bytes_used > self.limits.heap_limit_bytes {
346
+ return Err(serialization_error(
347
+ "snapshot validation failed: heap usage exceeds configured heap limit",
348
+ ));
349
+ }
350
+ if allocation_count > self.limits.allocation_budget {
351
+ return Err(serialization_error(
352
+ "snapshot validation failed: allocation count exceeds configured allocation budget",
353
+ ));
354
+ }
355
+
356
+ self.heap_bytes_used = heap_bytes_used;
357
+ self.allocation_count = allocation_count;
358
+ Ok(())
359
+ }
360
+
361
+ pub(super) fn refresh_promise_accounting(&mut self, key: PromiseKey) -> MustardResult<()> {
362
+ let (old_bytes, new_bytes) = {
363
+ let promise = self
364
+ .promises
365
+ .get(key)
366
+ .ok_or_else(|| MustardError::runtime("promise missing"))?;
367
+ (promise.accounted_bytes, measure_promise_bytes(promise))
368
+ };
369
+ self.apply_heap_delta(old_bytes, new_bytes)?;
370
+ self.promises
371
+ .get_mut(key)
372
+ .ok_or_else(|| MustardError::runtime("promise missing"))?
373
+ .accounted_bytes = new_bytes;
374
+ Ok(())
375
+ }
376
+
377
+ pub(super) fn recompute_accounting_totals(&mut self) -> Result<(usize, usize), String> {
378
+ let mut heap_bytes_used = 0usize;
379
+ let mut allocation_count = 0usize;
380
+
381
+ for env in self.envs.values_mut() {
382
+ env.accounted_bytes = measure_env_bytes(env);
383
+ heap_bytes_used = heap_bytes_used
384
+ .checked_add(env.accounted_bytes)
385
+ .ok_or_else(|| "heap accounting overflow".to_string())?;
386
+ allocation_count += 1;
387
+ }
388
+ for cell in self.cells.values_mut() {
389
+ cell.accounted_bytes = measure_cell_bytes(cell);
390
+ heap_bytes_used = heap_bytes_used
391
+ .checked_add(cell.accounted_bytes)
392
+ .ok_or_else(|| "heap accounting overflow".to_string())?;
393
+ allocation_count += 1;
394
+ }
395
+ for object in self.objects.values_mut() {
396
+ object.accounted_bytes = measure_object_bytes(object);
397
+ heap_bytes_used = heap_bytes_used
398
+ .checked_add(object.accounted_bytes)
399
+ .ok_or_else(|| "heap accounting overflow".to_string())?;
400
+ allocation_count += 1;
401
+ }
402
+ for array in self.arrays.values_mut() {
403
+ array.accounted_bytes = measure_array_bytes(array);
404
+ heap_bytes_used = heap_bytes_used
405
+ .checked_add(array.accounted_bytes)
406
+ .ok_or_else(|| "heap accounting overflow".to_string())?;
407
+ allocation_count += 1;
408
+ }
409
+ for map in self.maps.values_mut() {
410
+ map.accounted_bytes = measure_map_bytes(map);
411
+ heap_bytes_used = heap_bytes_used
412
+ .checked_add(map.accounted_bytes)
413
+ .ok_or_else(|| "heap accounting overflow".to_string())?;
414
+ allocation_count += 1;
415
+ }
416
+ for set in self.sets.values_mut() {
417
+ set.accounted_bytes = measure_set_bytes(set);
418
+ heap_bytes_used = heap_bytes_used
419
+ .checked_add(set.accounted_bytes)
420
+ .ok_or_else(|| "heap accounting overflow".to_string())?;
421
+ allocation_count += 1;
422
+ }
423
+ for iterator in self.iterators.values_mut() {
424
+ iterator.accounted_bytes = measure_iterator_bytes(iterator);
425
+ heap_bytes_used = heap_bytes_used
426
+ .checked_add(iterator.accounted_bytes)
427
+ .ok_or_else(|| "heap accounting overflow".to_string())?;
428
+ allocation_count += 1;
429
+ }
430
+ for closure in self.closures.values_mut() {
431
+ closure.accounted_bytes = measure_closure_bytes(closure);
432
+ heap_bytes_used = heap_bytes_used
433
+ .checked_add(closure.accounted_bytes)
434
+ .ok_or_else(|| "heap accounting overflow".to_string())?;
435
+ allocation_count += 1;
436
+ }
437
+ for promise in self.promises.values_mut() {
438
+ promise.accounted_bytes = measure_promise_bytes(promise);
439
+ heap_bytes_used = heap_bytes_used
440
+ .checked_add(promise.accounted_bytes)
441
+ .ok_or_else(|| "heap accounting overflow".to_string())?;
442
+ allocation_count += 1;
443
+ }
444
+
445
+ Ok((heap_bytes_used, allocation_count))
446
+ }
447
+ }
448
+
449
+ fn extra_value_bytes(value: &Value) -> usize {
450
+ match value {
451
+ Value::String(value) | Value::HostFunction(value) => value.len(),
452
+ Value::BigInt(value) => value.to_signed_bytes_le().len(),
453
+ _ => 0,
454
+ }
455
+ }
456
+
457
+ fn measure_bindings_bytes(bindings: &IndexMap<String, CellKey>) -> usize {
458
+ bindings.len() * std::mem::size_of::<(String, CellKey)>()
459
+ + bindings.keys().map(|key| key.len()).sum::<usize>()
460
+ }
461
+
462
+ fn measure_properties_bytes(properties: &IndexMap<String, Value>) -> usize {
463
+ properties.len() * std::mem::size_of::<(String, Value)>()
464
+ + properties
465
+ .iter()
466
+ .map(|(key, value)| key.len() + extra_value_bytes(value))
467
+ .sum::<usize>()
468
+ }
469
+
470
+ fn measure_env_bytes(env: &Env) -> usize {
471
+ std::mem::size_of::<Env>() + measure_bindings_bytes(&env.bindings)
472
+ }
473
+
474
+ fn measure_cell_bytes(cell: &Cell) -> usize {
475
+ std::mem::size_of::<Cell>() + extra_value_bytes(&cell.value)
476
+ }
477
+
478
+ fn measure_object_bytes(object: &PlainObject) -> usize {
479
+ std::mem::size_of::<PlainObject>()
480
+ + measure_properties_bytes(&object.properties)
481
+ + match &object.kind {
482
+ ObjectKind::FunctionPrototype(constructor) => extra_value_bytes(constructor),
483
+ ObjectKind::BoundFunction(bound) => {
484
+ extra_value_bytes(&bound.target)
485
+ + extra_value_bytes(&bound.this_value)
486
+ + bound.args.iter().map(extra_value_bytes).sum::<usize>()
487
+ }
488
+ ObjectKind::Error(name) => name.len(),
489
+ ObjectKind::RegExp(regex) => regex.pattern.len() + regex.flags.len(),
490
+ ObjectKind::StringObject(value) => value.len(),
491
+ _ => 0,
492
+ }
493
+ }
494
+
495
+ fn measure_array_bytes(array: &ArrayObject) -> usize {
496
+ std::mem::size_of::<ArrayObject>()
497
+ + array.elements.len() * std::mem::size_of::<Option<Value>>()
498
+ + array
499
+ .elements
500
+ .iter()
501
+ .filter_map(Option::as_ref)
502
+ .map(extra_value_bytes)
503
+ .sum::<usize>()
504
+ + measure_properties_bytes(&array.properties)
505
+ }
506
+
507
+ fn measure_map_bytes(map: &MapObject) -> usize {
508
+ std::mem::size_of::<MapObject>()
509
+ + map.entries.len() * std::mem::size_of::<MapEntry>()
510
+ + map
511
+ .entries
512
+ .iter()
513
+ .map(|entry| extra_value_bytes(&entry.key) + extra_value_bytes(&entry.value))
514
+ .sum::<usize>()
515
+ }
516
+
517
+ fn measure_set_bytes(set: &SetObject) -> usize {
518
+ std::mem::size_of::<SetObject>()
519
+ + set.entries.len() * std::mem::size_of::<Value>()
520
+ + set.entries.iter().map(extra_value_bytes).sum::<usize>()
521
+ }
522
+
523
+ fn measure_iterator_bytes(iterator: &IteratorObject) -> usize {
524
+ let state_bytes = match &iterator.state {
525
+ IteratorState::String(state) => state.value.len(),
526
+ IteratorState::Array(_)
527
+ | IteratorState::ArrayKeys(_)
528
+ | IteratorState::ArrayEntries(_)
529
+ | IteratorState::MapEntries(_)
530
+ | IteratorState::MapKeys(_)
531
+ | IteratorState::MapValues(_)
532
+ | IteratorState::SetEntries(_)
533
+ | IteratorState::SetValues(_) => 0,
534
+ };
535
+ std::mem::size_of::<IteratorObject>() + state_bytes
536
+ }
537
+
538
+ fn measure_closure_bytes(closure: &Closure) -> usize {
539
+ std::mem::size_of::<Closure>()
540
+ + closure.name.as_ref().map_or(0, String::len)
541
+ + extra_value_bytes(&closure.this_value)
542
+ + measure_properties_bytes(&closure.properties)
543
+ }
544
+
545
+ fn measure_promise_bytes(promise: &PromiseObject) -> usize {
546
+ let state_bytes = match &promise.state {
547
+ PromiseState::Pending => 0,
548
+ PromiseState::Fulfilled(value) => extra_value_bytes(value),
549
+ PromiseState::Rejected(rejection) => {
550
+ extra_value_bytes(&rejection.value)
551
+ + rejection
552
+ .traceback
553
+ .iter()
554
+ .map(|frame| frame.function_name.as_ref().map_or(0, String::len))
555
+ .sum::<usize>()
556
+ }
557
+ };
558
+ let reaction_bytes = promise
559
+ .reactions
560
+ .iter()
561
+ .map(|reaction| match reaction {
562
+ PromiseReaction::Then {
563
+ on_fulfilled,
564
+ on_rejected,
565
+ ..
566
+ } => on_fulfilled
567
+ .iter()
568
+ .chain(on_rejected.iter())
569
+ .map(extra_value_bytes)
570
+ .sum::<usize>(),
571
+ PromiseReaction::Finally { callback, .. } => {
572
+ callback.iter().map(extra_value_bytes).sum::<usize>()
573
+ }
574
+ PromiseReaction::FinallyPassThrough {
575
+ original_outcome, ..
576
+ } => match original_outcome {
577
+ PromiseOutcome::Fulfilled(value) => extra_value_bytes(value),
578
+ PromiseOutcome::Rejected(rejection) => extra_value_bytes(&rejection.value),
579
+ },
580
+ PromiseReaction::Combinator { .. } => 0,
581
+ })
582
+ .sum::<usize>();
583
+ let driver_bytes = match &promise.driver {
584
+ Some(PromiseDriver::Thenable { value }) => extra_value_bytes(value),
585
+ Some(PromiseDriver::All { values, .. }) => values
586
+ .iter()
587
+ .flatten()
588
+ .map(extra_value_bytes)
589
+ .sum::<usize>(),
590
+ Some(PromiseDriver::AllSettled { results, .. }) => results
591
+ .iter()
592
+ .flatten()
593
+ .map(|result| match result {
594
+ PromiseSettledResult::Fulfilled(value) | PromiseSettledResult::Rejected(value) => {
595
+ extra_value_bytes(value)
596
+ }
597
+ })
598
+ .sum::<usize>(),
599
+ Some(PromiseDriver::Any { reasons, .. }) => reasons
600
+ .iter()
601
+ .flatten()
602
+ .map(extra_value_bytes)
603
+ .sum::<usize>(),
604
+ None => 0,
605
+ };
606
+ std::mem::size_of::<PromiseObject>()
607
+ + promise.awaiters.len() * std::mem::size_of::<AsyncContinuation>()
608
+ + promise.dependents.len() * std::mem::size_of::<PromiseKey>()
609
+ + promise.reactions.len() * std::mem::size_of::<PromiseReaction>()
610
+ + state_bytes
611
+ + reaction_bytes
612
+ + driver_bytes
613
+ }