1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//! Process-global record-shape registry (#462 slice 3).
//!
//! Maps sorted field-name lists to stable `u32` shape IDs for records
//! built at runtime — JSON decode, SQL row, HTTP body, host effect
//! handlers, builtin returns. Anywhere `Value::record_dynamic` is
//! called.
//!
//! Why: the slice-2b measurement (`docs/design/ic-polymorphism-measurement.md`)
//! found 14% of GetField IC hits — and 100% of inbox/gateway/std_http
//! traffic — landed on records carrying `NO_SHAPE_ID`. Those records
//! all aliased on the sentinel, so the IC's shape-keyed verification
//! (added in #517) couldn't distinguish them and fell through to the
//! name-compare path on every hit. With this registry, dynamic records
//! built from the same field set share a real `shape_id` and the IC
//! hits cleanly amongst them.
//!
//! ## Disjoint ID spaces
//!
//! Compile-time `Op::MakeRecord` shape IDs come from
//! `Program::record_shapes` and are per-program indices (0, 1, 2, …).
//! Runtime registry IDs come from this module and live in the high
//! half of the `u32` range starting at [`DYNAMIC_SHAPE_ID_BASE`].
//! `NO_SHAPE_ID` (`u32::MAX`) is reserved.
//!
//! Disjoint spaces are required for IC correctness: the shape-keyed
//! verifier in `vm.rs` treats `cached_shape == incoming_shape` as
//! "offset is sound" for non-`NO_SHAPE_ID` cases. If a compile-time
//! ID collided with a dynamic ID for a different field set, the IC
//! would return values from the wrong field.
//!
//! ## Cost
//!
//! One `RwLock<IndexMap>` lookup per `record_dynamic` call. The map
//! grows monotonically (shapes are never freed) but is small in
//! practice — tens of distinct shapes per workload. Lookups are
//! read-lock + hash; misses take the write lock once per new shape.
//!
//! ## Sorting
//!
//! The key is the sorted field-name vec — two records with the same
//! fields in different insertion order share a `shape_id`. Matches
//! the existing `Value::Record` `PartialEq` (which compares `IndexMap`
//! contents structurally, ignoring `shape_id`), so equality and IC
//! sharing line up.
use IndexMap;
use ;
/// Base for dynamically-interned shape IDs. Chosen so that
/// `Program::record_shapes` indices (which start at 0 and grow up)
/// cannot collide with dynamic IDs even for pathologically large
/// programs. Compile-time records will hit a different IC slot
/// outcome than dynamic records with the same field set — that's
/// the cost of keeping ID spaces disjoint; the slice-2b
/// measurement found 0 mixed-flavor sites in real workloads.
pub const DYNAMIC_SHAPE_ID_BASE: u32 = 0x8000_0000;
/// Look up (or assign) the shape ID for the given field-name list.
/// Same set of names — in any insertion order — yields the same ID
/// for the lifetime of the process.