Repository navigation
Grain: index the constant pool by hash - #1202
Conversation
|
Suggestion: A hash is considered absolute. It already hashes the type of the data, so an int will not match a char ot a bool or a string. Custom types will never arrive into constants since they are not poolable. The recognized ones are handled by the hashing. Rhai assumes that such hashing is unique so there is no need to consider collisions - it is assumed to be practically impossible in Rhai. So the index can simply map to one constant offset and there is no need for |
|
@luispedro Would you have time to address this? I can make a PR with the revisions otherwise. :-D |
push_const found a duplicate by scanning the pool and rendering every
pooled constant with {:?} again for each new one, which made compiling
quadratic in the number of constants. A map literal with any
non-constant value made it much worse: its template, holding every key,
is pooled first, then each entry's key and value, and each of those
lookups rendered the whole template again.
Index the pool by each constant's hash, and on a hash match compare the
two constants (type first, strings directly, other values by
rendering). Only poolable constants are shared: anything else need not
be hashable, and two custom-type values render the same (as the type's
name) yet differ, so the old scan merged them. The pool keeps emission
order.
Compiling a 2000-entry map literal with one computed value goes from
~440 ms to ~0.4 ms.
Fixes rhaiscript#1196.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A constant's hash covers its type and Rhai treats it as unique, so a matching hash is the same constant; same_constant is not needed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4c2b332 to
15f1636
Compare
|
Updated, but always feel free to just take my stuff and edit/merge/discard.... |
I wonder what error this is... since the Grain constants pool should not even pool custom syntax... EDIT: I have fixed the merge conflicts. |
Fixes #1196, as discussed there: the constant pool is indexed by each
Dynamic's hash, so compile time is linear in the number of constants rather than quadratic.Changes
push_consthashes each constant withcalc_switch_value_hash. AStraightHashMapmaps each hash to the indices of the pooled constants with that hash.same_constantchecks that the two values really are equal: type first, strings directly, and other values by{:?}rendering. A hash collision cannot merge two different constants.constant_capsisSome) are deduplicated; anything else is appended.Dynamic::hashpanics on custom types and timestamps, so this is required. It also fixes an existing bug: custom-type values all render as their type name, so the old scan merged distinct ones. For example, with two custom-syntax states of a custom type,[tag 1, tag 2]returned[1, 1]under Grain. The new testcustom_type_states_stay_apartfails onmainand passes here.Expr::Mapin the compiler now says what the parser's template actually holds (every key with()as its value).The parser-side change (putting constant values in the map template so they can be skipped during evaluation) is left for a separate PR, as suggested in the issue.
Timing
The repro from the issue: Grain compile only, release build, median of 11 compiles.
main(from the issue)BTreeMap<String, u32>)Checks
cargo test --features internals,grain --testsand--libpass.cargo fmt --all -- --checkpasses. Clippy reports nothing on the changed code.cargo checkis warning-free withgrainplus each ofno_object,no_index,no_float,no_closure,sync,no_custom_syntax,no_function, andonly_i32,f32_float,decimal. Theno_std,grainbuild has the same 3 warnings asmain.🤖 Generated with Claude Code