about summary refs log tree commit diff
path: root/tvix/eval/src/compiler/scope.rs
AgeCommit message (Collapse)AuthorFilesLines
2024-08-07 r/8453 feat(tvix/eval): Forbid Hash{Map,Set}, use Fx insteadAspen Smith1-5/+3
Per https://nnethercote.github.io/perf-book/hashing.html, we have basically no reason to use the default hasher over a faster, non-DoS-resistant hasher. This gives a nice perf boost basically for free: hello outpath time: [704.76 ms 714.91 ms 725.63 ms] change: [-7.2391% -6.1018% -4.9189%] (p = 0.00 < 0.05) Performance has improved. Change-Id: If5587f444ed3af69f8af4eead6af3ea303b4ae68 Reviewed-on: https://cl.tvl.fyi/c/depot/+/12046 Tested-by: BuildkiteCI Reviewed-by: flokli <flokli@flokli.de> Reviewed-by: Ilan Joselevich <personal@ilanjoselevich.com> Autosubmit: aspen <root@gws.fyi>
2024-07-05 r/8345 feat(tvix/eval): Allow passing in an env to evaluationAspen Smith1-5/+26
Allow passing in a top-level env, a map from name to value, to evaluation. The intent is to support bound identifiers in the REPL just like upstream nix does. Getting this working involves mucking around a bit with internals - most notably, locals now only optionally have a Span (since locals don't have an easy span we can use) - and getting that working requires propagating some minor hacks to places where we currently *need* a span (and which would require too much changing now to make spans optional; my guess is that that would essentially end up making spans optional throughout the codebase). Also, some extra care has to be taken to close out the scope in the case that we do pass in an env, to avoid breaking our assumptions about the size of the stack when we return from the toplevel Change-Id: Ie475b2d3dfc72ccbf298d2a3ea28c63ac877d653 Reviewed-on: https://cl.tvl.fyi/c/depot/+/11953 Tested-by: BuildkiteCI Autosubmit: aspen <root@gws.fyi> Reviewed-by: flokli <flokli@flokli.de>
2023-01-21 r/5721 refactor(tvix/eval): administer antidote for poisonAdam Joseph1-42/+4
The codebase contains a lot of complexity and odd roundabout handling for shadowing globals. I'm pretty sure none of this is necessary, and all of it disappears if you simply make the globals part of the ordinary identifier resolution chain, with their own scope up above the root scope. Then the ordinary shadowing routines do the right thing, and no special cases or new terminology are required. This commit does that. Note by tazjin: This commit was originally abandoned when Adam decided not to take away reviewer bandwidth for this at the time (eval was still in a much earlier stage). As we've recently done some significant refactoring of globals initialisation this came up again, and it seems we can easily cover the use-cases of the poison tracking in other ways now, so I've rebased, updated and resurrected the CL. Co-Authored-By: Vincent Ambo <tazjin@tvl.su> Signed-off-by: Adam Joseph <adam@westernsemico.com> Change-Id: Ib3309a47a7b31fa5bf10466bade0d876b76ae462 Reviewed-on: https://cl.tvl.fyi/c/depot/+/7089 Reviewed-by: tazjin <tazjin@tvl.su> Tested-by: BuildkiteCI Reviewed-by: flokli <flokli@flokli.de>
2023-01-06 r/5598 fix(tvix/eval): don't increase `with_stack_size` in scope inheritsVincent Ambo1-1/+1
There was probably a misunderstanding somewhere about the with_stack_size being related to how far away it is from the with, but it is about whether there is a with at all. This broke a warning (`UselessInherit`), and may actually have let to more inefficient codegen in some cases. Change-Id: I08338ea59ae39dad01ca8a4e09d934a936cdea2f Reviewed-on: https://cl.tvl.fyi/c/depot/+/7762 Reviewed-by: flokli <flokli@flokli.de> Tested-by: BuildkiteCI
2022-12-21 r/5454 refactor(tvix/eval): add name-based index over compiler's localsVincent Ambo1-28/+101
Instead of finding locals by doing 2x O(n) walks over the compiler's locals list, use a secondary name-based index for resolving locals by name. Previously, almost 60% (!!) of eval time on some expressions over nixpkgs was spent in `Local::has_name`. This function doesn't even exist anymore now, and eval speed about doubles as a result. Note that this doesn't exactly make the locals code easier to read, but I'm also not sure what we can simplify in there in general. This fixes b/227. Change-Id: I29ce5eb9452b02d3b358c673e1f5cf8082e2fef9 Reviewed-on: https://cl.tvl.fyi/c/depot/+/7560 Reviewed-by: grfn <grfn@gws.fyi> Tested-by: BuildkiteCI
2022-11-05 r/5251 fix(tvix/eval): Scope.inherit(): fix scope_depth, with_stack_depthAdam Joseph1-0/+2
Scope_depth and with_stack_depth were being reset to zero for nested function abstractions. Fortunately nothing depends on them being computed correctly in these cases, but it sure was confusing. Change-Id: I59980b6a5aff043f60079f97211220b0086eb97d Signed-off-by: Adam Joseph <adam@westernsemico.com> Reviewed-on: https://cl.tvl.fyi/c/depot/+/7091 Reviewed-by: tazjin <tazjin@tvl.su> Tested-by: BuildkiteCI
2022-11-04 r/5237 fix(tvix/eval): inline mis-named Local::above()Adam Joseph1-6/+1
If self.depth > other.depth then self is deeper than other, so self is *below* other, not above it. Let's just inline the function. Change-Id: I8dda3d90cbc86c8a6fa01bc4a5e506a2e403bd20 Signed-off-by: Adam Joseph <adam@westernsemico.com> Reviewed-on: https://cl.tvl.fyi/c/depot/+/7090 Reviewed-by: tazjin <tazjin@tvl.su> Tested-by: BuildkiteCI
2022-10-26 r/5201 docs(tvix/eval): StackIdx, LocalIdx UpvalueIdxAdam Joseph1-3/+1
This adds a comment noting that StackIdx is an offset relative to the base of the current CallFrame, whereas UpvalueIdx is an absolute index into the upvalues array. It also removes the confusing mention of StackIdx in the descriptive comment for LocalIdx. They index into totally different structures; one exists at runtime and the other exists at compile time. Change-Id: Ib932b1b0679734c15001e8c5c95a08293fa016b4 Signed-off-by: Adam Joseph <adam@westernsemico.com> Reviewed-on: https://cl.tvl.fyi/c/depot/+/7017 Reviewed-by: grfn <grfn@gws.fyi> Reviewed-by: tazjin <tazjin@tvl.su> Tested-by: BuildkiteCI
2022-10-23 r/5186 feat(tvix/eval): initial attempt at setting lambda namesVincent Ambo1-0/+10
When compiling a lambda, take the name of the outer slot (if available) and store it as the name on the lambda. These names are then shown in the observer, and nowhere else (so far). It is of course common for these things to thread through many different context levels (e.g. `f = a: b: c: ...`), in this setup only the outermost closure or thunk gains the name, but it's better than nothing. Change-Id: I681ba74e624f2b9e7a147144a27acf364fe6ccc7 Reviewed-on: https://cl.tvl.fyi/c/depot/+/7065 Reviewed-by: grfn <grfn@gws.fyi> Autosubmit: tazjin <tazjin@tvl.su> Tested-by: BuildkiteCI
2022-10-19 r/5159 feat(tvix/eval): deduplicate overlap between Closure and ThunkAdam Joseph1-0/+11
This commit deduplicates the Thunk-like functionality from Closure and unifies it with Thunk. Specifically, we now have one and only one way of breaking reference cycles in the Value-graph: Thunk. No other variant contains a RefCell. This should make it easier to reason about the behavior of the VM. InnerClosure and UpvaluesCarrier are no longer necessary. This refactoring allowed an improvement in code generation: `Rc<RefCell<>>`s are now created only for closures which do not have self-references or deferred upvalues, instead of for all closures. OpClosure has been split into two separate opcodes: - OpClosure creates non-recursive closures with no deferred upvalues. The VM will not create an `Rc<RefCell<>>` when executing this instruction. - OpThunkClosure is used for closures with self-references or deferred upvalues. The VM will create a Thunk when executing this opcode, but the Thunk will start out already in the `ThunkRepr::Evaluated` state, rather than in the `ThunkRepr::Suspeneded` state. To avoid confusion, OpThunk has been renamed OpThunkSuspended. Thanks to @sterni for suggesting that all this could be done without adding an additional variant to ThunkRepr. This does however mean that there will be mutating accesses to `ThunkRepr::Evaluated`, which was not previously the case. The field `is_finalised:bool` has been added to `Closure` to ensure that these mutating accesses are performed only on finalised Closures. Both the check and the field are present only if `#[cfg(debug_assertions)]`. Change-Id: I04131501029772f30e28da8281d864427685097f Signed-off-by: Adam Joseph <adam@westernsemico.com> Reviewed-on: https://cl.tvl.fyi/c/depot/+/7019 Tested-by: BuildkiteCI Reviewed-by: tazjin <tazjin@tvl.su>
2022-09-22 r/4958 fix(tvix/eval): support string identifiers in inheritsVincent Ambo1-1/+1
This updates rnix-parser to a version where inherits provide an iterator over `ast::Attr` instead of `ast::Ident`, which mirrors the behaviour of Nix (inherits can have (statically known) strings as their identifiers). This actually required some fairly significant code reshuffling in the compiler, as there was an implicit assumption in many places that we would have an `ast::Ident` node available when dealing with variable access (which is then explicitly only not true in this case). Change-Id: I12f1e786c0030c85107b1aa409bd49adb5465546 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6747 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
2022-09-13 r/4841 chore(tvix/eval): do not inherit scope depth in new scopesVincent Ambo1-1/+0
This is no longer required, resolution is now more sane. Pointed out by sterni in cl/6422. Change-Id: Icc8983c648f864e66813948df6e2d4bad6a7f312 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6565 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
2022-09-13 r/4840 refactor(tvix/eval): encapsulate scope_depth in compiler::scopeVincent Ambo1-1/+12
This field no longer needs to be directly accessible by the compiler. Addresses a sterni lint from cl/6466 Change-Id: I5e6791943d7f0ab3d9b7a30bb1654c4a6a435b1f Reviewed-on: https://cl.tvl.fyi/c/depot/+/6564 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
2022-09-11 r/4813 fix(tvix/eval): reduce scope depth in scope moduleVincent Ambo1-0/+2
Change-Id: If32f9e4c9212f20a39baa15d479ff1387c17570d Reviewed-on: https://cl.tvl.fyi/c/depot/+/6500 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
2022-09-11 r/4801 refactor(tvix/eval): capture entire with_stack in upvaluesVincent Ambo1-13/+0
This completely rewrites the handling of "dynamic upvalues" to, instead of resolving them at thunk/closure instantiation time (which forces some values too early), capture the entire with stack of parent contexts if it exists. There are a couple of things in here that could be written more efficiently, but I'm first working through this to get to a bug related to with + recursion and the code complexity of some of the optimisations is distracting. Change-Id: Ia538e06c9146e3bf8decb9adf02dd726d2c651cf Reviewed-on: https://cl.tvl.fyi/c/depot/+/6486 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
2022-09-11 r/4795 refactor(tvix/eval): add `initialised` arg to declare_phantomVincent Ambo1-3/+3
There are more upcomming uses of declare_phantom where this will come in handy to avoid some code bloat. Change-Id: I75cad8caf14511c519ab2f56e87e99bcbf0a082e Reviewed-on: https://cl.tvl.fyi/c/depot/+/6467 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
2022-09-11 r/4794 refactor(tvix/eval): encapsulate scope cleanup logic in moduleVincent Ambo1-4/+45
Moves the logic for removing tracked locals from a given scope from the compiler's locals list, and leaves only the actual compiler-related stuff (emitting warnings, cleaning up locals at runtime) in the compiler itself. Change-Id: I9da6eb54967f0a7775f624d602fe11be4c7ed5c4 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6466 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
2022-09-10 r/4786 fix(tvix/eval): fix doc comment syntax where applicableVincent Ambo1-17/+17
As pointed out by grfn on cl/6091 Change-Id: I28308577b7cf99dffb4a4fd3cc8783eb9ab4d0d6 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6460 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
2022-09-09 r/4781 chore(tvix/eval): clean up a stale commentVincent Ambo1-4/+0
Change-Id: If1b02fe1c78398387ea98490e5b099f1ff1b4164 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6455 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
2022-09-08 r/4763 fix(tvix/eval): address current clippy & grfn lintsVincent Ambo1-4/+5
Change-Id: I65c6feb9f817b5b367d37204a1f57acfe4100d97 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6430 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
2022-09-08 r/4757 fix(tvix/eval): ensure that root stack slot actually existsVincent Ambo1-4/+0
Instead of using a sentinel LocalIdx which potentially points to a value in the locals stack that does not actually exist, set up an initial uninitialised phantom value representing the result of the root expression. Change-Id: I82ea774daab83168020a3850bed57d35ab25c7df Reviewed-on: https://cl.tvl.fyi/c/depot/+/6424 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
2022-09-08 r/4755 fix(tvix/eval): propagate scope depth when nesting scopesVincent Ambo1-0/+1
Change-Id: Id441646db550f6195c2e247a0afbb5c9d91da8a0 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6422 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
2022-09-08 r/4754 refactor(tvix/eval): refactor locals to use an enum for phantomsVincent Ambo1-14/+36
Instead of using sentinel values and an additional bool, this tracks the identifier of a local as an enum that is either a statically known name, or a phantom. To make this work correctly some more locals related logic has been encapsulated in the `scope` module, which is a good thing (that's the goal). Phantom values are now not initialised by default, but the only current call site of phantoms (`with` expression compilation) performs the initialisation right away. This commit changes no actual functionality right now, but paves the way for fixing an issue related to `let` bodies. Change-Id: I679f93a59a4daeacfe40f4012263cfb7bc05034e Reviewed-on: https://cl.tvl.fyi/c/depot/+/6421 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
2022-09-08 r/4753 refactor(tvix/eval): always pass slot to compiler methodsVincent Ambo1-0/+4
The slot is now always known (at the root of the file it is simply stack slot 0 once the scope drops back down to 0), so it does not need to be wrapped in an `Option` and accessed in cumbersome ways anymore. Change-Id: I46bf67a4cf5cb96e4874dffd0e3fb07c551d44f0 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6420 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
2022-09-08 r/4743 fix(tvix/eval): inherit scope poisoning data in nested contextsVincent Ambo1-0/+9
Scope poisoning must be inherited across lambda context boundaries, e.g. if an outer scope has a poisoned `null`, any lambdas defined on the same level must reference that poisoned identifier correctly. Change-Id: I1aac64e1c048a6f3bacadb6d78ed295fa439e8b4 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6410 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
2022-09-07 r/4737 refactor(tvix/eval): store spans instead of nodes in Warning/ErrorVincent Ambo1-6/+6
Another step towards being able to report accurate errors. The codemap spans contain strictly more accessible information, as they now retain information about which input file something came from. This required some shuffling around in the compiler to thread all the right information to the right places. Change-Id: I18ccfb20f07b0c33e1c4f51ca00cd09f7b2d19c6 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6404 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
2022-09-07 r/4733 feat(tvix/eval): track source spans for upvaluesVincent Ambo1-0/+1
With this change, the upvalue data instructions used by finalisers for thunks and closures track the source span of the first identifier that created the upvalue (if the same value is closed over multiple times the upvalue will be reused, hence only the first one). To do this the upvalue struct used by the compiler's scope now carries an identifier node, which had to be threaded through quite a few places. Change-Id: I15a5fcb4c8abbd48544a2325f297a5ad14ec06ae Reviewed-on: https://cl.tvl.fyi/c/depot/+/6400 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
2022-09-07 r/4732 refactor(tvix/eval): split out Upvalue struct & UpvalueKind enumVincent Ambo1-1/+6
This separation makes it possible to annotate the upvalue itself with the span that created it, which (due to upvalue reuse) is only the first one for an instance of the given UpvalueKind. Change-Id: I9a991da6a3e8d71a92f981314bed900bcf434d44 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6399 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
2022-09-07 r/4706 fix(tvix/eval): address current clippy lintsVincent Ambo1-2/+2
Note that I've allowed `needless_lifetimes` for the attribute set iterator, as I find the type easier to understand with these annotations present. Change-Id: I33abb17837ee4813076cdb9a87f54bac4a37044e Reviewed-on: https://cl.tvl.fyi/c/depot/+/6373 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
2022-09-07 r/4695 chore(tvix/eval): implement Debug for compiler::scope::ScopeVincent Ambo1-1/+2
Change-Id: I112b0119bd0511f26bb72f7e73d867d1b7144a36 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6359 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
2022-09-06 r/4670 fix(tvix/eval): distinguish statically between StackIdx and LocalIdxVincent Ambo1-21/+79
Previously the functions in the scope module returned usize values, which - sometimes from the same function - were either indexes into the runtime stack *or* indexes into the compiler's local stack. This is extremely confusing because it requires the caller to be aware of the difference, and it actually caused subtle bugs. To avoid this, there is now a new LocalIdx wrapper type which is used by the scope module to return indexes into the compiler's stack, as well as helpers for accounting for the differences between these indexes and the runtime indexes. Change-Id: I58f0b50ad94b28a304e3372fd9731b6590b3fdb8 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6340 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
2022-09-06 r/4668 feat(tvix/eval): track whether locals needs to be finalisedVincent Ambo1-0/+4
When encountering a deferred local upvalue, the compiler will now mark the corresponding local as needing a finaliser which makes it possible to emit the OpFinalise instruction for this stack slot a little bit down the line. Change-Id: I3962066f10fc6c6e1472722b8bdb415a811e0740 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6338 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
2022-09-06 r/4661 refactor(tvix/eval): decouple local depth & initialisation trackingVincent Ambo1-40/+22
In order to resolve recursive references correctly, these two can not be initialised the same way as a potentially large number of (nested!) locals can be declared without initialising their depth. This would lead to issues with detecting things like shadowed variables, so making both bits explicit is preferable. Change-Id: I100cdf1724faa4a2b5a0748429841cf8ef206252 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6325 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
2022-09-06 r/4657 refactor(tvix/eval): thread dynamic upvalues through all contextsVincent Ambo1-2/+9
With this change, encountering a dynamic upvalue will thread through all contexts starting from the lowest context that has a non-empty `with`-stack. The additional upvalues are not actually used yet, so the effective behaviour remains mostly the same. This is done in preparation for an upcoming change, which will implement proper dynamic resolution for complex cases of nested dynamic upvalues. Yes, this whole upvalue + dynamic values thing is a little bit mind-bending, but we would like to not give up being able to resolve a large chunk of the scoping behaviour statically. Change-Id: Ia58cdd47d79212390a6503ef13cef46b6b3e19a2 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6321 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
2022-09-04 r/4643 refactor(tvix/eval): track with stack size as a simple integerVincent Ambo1-7/+18
The `With` struct no longer contained any internals after the cleanup logic for the stack had been moved into Compiler::compile_with, leaving the `Vec<With>` to essentially act as a counter for the number of things on the with stack. That's inefficient of course, so with this commit it actually becomes an integer (with an encapsulated API within scope::Scope). Change-Id: I67a00987fc8b46b30d369a96d41e83c8af5b1998 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6311 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
2022-09-04 r/4642 refactor(tvix/eval): move compiler's scope logic to separate moduleVincent Ambo1-0/+189
The compiler module is getting quite long and this will help keep some order. Right now the scope internals are not very well encapsulated; this paves a way to reducing the API surface of the `scope` type to the things that are actually used by the compiler instead of giving access to its internals. Change-Id: I8c16c26d263f018baa263f395c9cd80715199241 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6310 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>