Commit Graph
20481 Commits
Author SHA1 Message Date
Joe Savona b876f545a5 Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-06 12:58:09 -07:00
Joe Savona 725b73ac39 Update base for Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-06 12:58:09 -07:00
Joe Savona a84afcc438 Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-06 12:42:20 -07:00
Joe Savona 59951e31c1 Update base for Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-06 12:42:19 -07:00
Joe Savona 8206c2caf4 Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-06 09:56:52 -07:00
Joe Savona 57b9907acc Update base for Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-06 09:56:51 -07:00
Joe Savona 5a795f6add Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-05 22:13:25 -07:00
Joe Savona 0b46330aed Update base for Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-05 22:13:25 -07:00
Joe Savona 5c3732917c Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-05 14:17:05 -07:00
Joe Savona a11a15c6bd Update base for Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-05 14:17:04 -07:00
Joe Savona 495cc48544 Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-05 14:00:35 -07:00
Joe Savona 0e0030c3c3 Update base for Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-05 14:00:34 -07:00
Joe Savona 91ea9ab005 Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-04 17:00:57 -07:00
Joe Savona 000447a36a Update base for Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-04 17:00:56 -07:00
Joe Savona bbceb06909 Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-04 16:48:09 -07:00
Joe Savona 907469fcd5 Update base for Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-04 16:48:08 -07:00
Joe Savona ee88580e18 Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-03 17:00:47 -07:00
Joe Savona b5ebeda949 Update base for Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-03 17:00:47 -07:00
Joe Savona f9f9e278d5 Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-03 11:33:51 -07:00
Joe Savona 61606a48b3 Update base for Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-03 11:33:50 -07:00
Joe Savona f166ada125 Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-03 09:01:28 -07:00
Joe Savona f793f387c8 Update base for Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-03 09:01:27 -07:00
Joe Savona 52bd1a1be4 Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-01 17:19:49 -07:00
Joe Savona 94c8839d81 Update base for Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-06-01 17:19:49 -07:00
Joe Savona 411e50f2c2 Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-05-30 16:30:01 -07:00
Joe Savona 1718763795 Update base for Update on "[compiler] Distinguish Alias/Assign effects"
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-05-30 16:30:01 -07:00
Joe Savona 207cf384b0 [compiler] Distinguish Alias/Assign effects
Alias was akward becuase it had a specific data flow / mutability relationship — direct mutations affect both sides - but also populated the output. We need the ability to express the aliasing dataflwo/mutability relationship w/o expressing actual assignment.

An example of this is that for an unknown method call `const z = x.y()`, we want to express the Alias-style mutability relationship btw z and x (Muate(z) => Mutate(x)), but we want to assume that `z !== x`.

This ends up being really clean, the places that should use Assign are very obvious (LoadLocal, StoreLocal) and most places keep using Alias.

[ghstack-poisoned]
2025-05-30 15:57:18 -07:00
Joe Savona e44415480d Update on "[compiler] Effect inference across signatures and user-provided callbacks"
This ties all the ideas together, showing the promise of the new inference. When applying effects, when we encounter an Apply effect we now check to see if the function we're calling is a locally defined FunctionExpression. If so, we construct a signature for it on the fly (we already have created the effects in AnalyzeFunctions), substitute in the args to get a set of effects we can apply, and then recursively apply those effects.

This required adding an ability for signatures to declare additional temporary places that they can reference. For example, Array.prototype.map needs a temporary to represent the items it extracts from the receiver array, and another temporary for the result of calling the user-provided function.

This also meant adding a `CreateFunction` effect which a) allows us to preserve the FunctionExpression value in the inference state (the previous Create effect meant we just created a dummy ObjectExpression) and b) allows dynamically constructing the ValueKind of the function based on whether it actually captures any mutable values.

Lots of other little fixes as well, such as changing function related effects (and PropertyLoad) to use Alias instead of Capture so that subsequent mutations of the output count as mutations of the input.

[ghstack-poisoned]
2025-05-30 15:57:16 -07:00
Joe Savona 37f3daa79d Update base for Update on "[compiler] Effect inference across signatures and user-provided callbacks"
This ties all the ideas together, showing the promise of the new inference. When applying effects, when we encounter an Apply effect we now check to see if the function we're calling is a locally defined FunctionExpression. If so, we construct a signature for it on the fly (we already have created the effects in AnalyzeFunctions), substitute in the args to get a set of effects we can apply, and then recursively apply those effects.

This required adding an ability for signatures to declare additional temporary places that they can reference. For example, Array.prototype.map needs a temporary to represent the items it extracts from the receiver array, and another temporary for the result of calling the user-provided function.

This also meant adding a `CreateFunction` effect which a) allows us to preserve the FunctionExpression value in the inference state (the previous Create effect meant we just created a dummy ObjectExpression) and b) allows dynamically constructing the ValueKind of the function based on whether it actually captures any mutable values.

Lots of other little fixes as well, such as changing function related effects (and PropertyLoad) to use Alias instead of Capture so that subsequent mutations of the output count as mutations of the input.

[ghstack-poisoned]
2025-05-30 15:57:16 -07:00
Joe Savona 79760fefcb [compiler] Effect inference across signatures and user-provided callbacks
This ties all the ideas together, showing the promise of the new inference. When applying effects, when we encounter an Apply effect we now check to see if the function we're calling is a locally defined FunctionExpression. If so, we construct a signature for it on the fly (we already have created the effects in AnalyzeFunctions), substitute in the args to get a set of effects we can apply, and then recursively apply those effects.

This required adding an ability for signatures to declare additional temporary places that they can reference. For example, Array.prototype.map needs a temporary to represent the items it extracts from the receiver array, and another temporary for the result of calling the user-provided function.

This also meant adding a `CreateFunction` effect which a) allows us to preserve the FunctionExpression value in the inference state (the previous Create effect meant we just created a dummy ObjectExpression) and b) allows dynamically constructing the ValueKind of the function based on whether it actually captures any mutable values.

Lots of other little fixes as well, such as changing function related effects (and PropertyLoad) to use Alias instead of Capture so that subsequent mutations of the output count as mutations of the input.

[ghstack-poisoned]
2025-05-30 11:33:45 -07:00
Joe Savona 68fd43acca Update on "[compiler] Receiver is mutate? for functions wo signatures"
[ghstack-poisoned]
2025-05-30 11:33:43 -07:00
Joe Savona c516349df5 Update base for Update on "[compiler] Receiver is mutate? for functions wo signatures"
[ghstack-poisoned]
2025-05-30 11:33:42 -07:00
Joe Savona 148aa1901f [compiler] Receiver is mutate? for functions wo signatures
[ghstack-poisoned]
2025-05-29 17:30:51 -07:00
Joe Savona 126541bca8 [compiler] Handle legacy mutableIfOperandsMutable signatures
[ghstack-poisoned]
2025-05-29 17:30:46 -07:00
Joe Savona 17c114a281 [compiler] Prep for making new/call/etc use Apply effects
[ghstack-poisoned]
2025-05-29 17:30:42 -07:00
Joe Savona ac2340e479 [compiler] Bailout on mutations of frozen/global values
[ghstack-poisoned]
2025-05-29 17:30:37 -07:00
Joe Savona eb8d0c27b0 [compiler] comments and todos
[ghstack-poisoned]
2025-05-29 17:30:33 -07:00
Joe Savona bc01ae2157 Update on "[compiler] Translate legacy FunctionSignature into new AliasingEffects"
To help bootstrap the new inference model, this PR adds a helper that takes a legacy FunctionSignature and converts into a list of (new) AliasingEffects. This conversion tries to make explicit all the implicit handling of InferReferenceEffects and previous FunctionSignature.

For example, the signature for Array.proto.pop has a calleeEffect of `Store`. Nowhere does it say that the receiver flows into the result! There's an implicit behavior that the receiver flows into the result. The new function makes this explicit by emitting a `Capture receiver -> lvalue` effect.

So far I confirmed that this works for Array.proto.push() if i hard code the inference to ignore new-style aliasing signatures. I'll continue to refine it going forward as I start running the new inference on more fixtures.

[ghstack-poisoned]
2025-05-29 17:30:31 -07:00
Joe Savona 3def726cac Update base for Update on "[compiler] Translate legacy FunctionSignature into new AliasingEffects"
To help bootstrap the new inference model, this PR adds a helper that takes a legacy FunctionSignature and converts into a list of (new) AliasingEffects. This conversion tries to make explicit all the implicit handling of InferReferenceEffects and previous FunctionSignature.

For example, the signature for Array.proto.pop has a calleeEffect of `Store`. Nowhere does it say that the receiver flows into the result! There's an implicit behavior that the receiver flows into the result. The new function makes this explicit by emitting a `Capture receiver -> lvalue` effect.

So far I confirmed that this works for Array.proto.push() if i hard code the inference to ignore new-style aliasing signatures. I'll continue to refine it going forward as I start running the new inference on more fixtures.

[ghstack-poisoned]
2025-05-29 17:30:30 -07:00
Joe Savona fd162bdd9d [compiler] Translate legacy FunctionSignature into new AliasingEffects
To help bootstrap the new inference model, this PR adds a helper that takes a legacy FunctionSignature and converts into a list of (new) AliasingEffects. This conversion tries to make explicit all the implicit handling of InferReferenceEffects and previous FunctionSignature.

For example, the signature for Array.proto.pop has a calleeEffect of `Store`. Nowhere does it say that the receiver flows into the result! There's an implicit behavior that the receiver flows into the result. The new function makes this explicit by emitting a `Capture receiver -> lvalue` effect.

So far I confirmed that this works for Array.proto.push() if i hard code the inference to ignore new-style aliasing signatures. I'll continue to refine it going forward as I start running the new inference on more fixtures.

[ghstack-poisoned]
2025-05-28 22:27:22 -07:00
Joe Savona 0d6822a1da Update on "[compiler] First example of an aliasing signature (array push)"
Adds an aliasing signature for Array.prototype.push and fixes up the logic for consuming these signatures during effect inference. As the test fixture shows, we correctly model the capturing. Mutable values that are captured into the array count as co-mutated if the array itself is transitively mutated later, while mutable values captured after such transitive mutation are not considered co-mutated.

The implementation is based on the fact that the final `push` call is only locally mutating the array. During the phase that looks at local mutations we are only tracking direct aliases, and the push doesn't directly alias the items to the array, it only captures them.

[ghstack-poisoned]
2025-05-28 22:27:20 -07:00
Joe Savona 93e24f467e Update base for Update on "[compiler] First example of an aliasing signature (array push)"
Adds an aliasing signature for Array.prototype.push and fixes up the logic for consuming these signatures during effect inference. As the test fixture shows, we correctly model the capturing. Mutable values that are captured into the array count as co-mutated if the array itself is transitively mutated later, while mutable values captured after such transitive mutation are not considered co-mutated.

The implementation is based on the fact that the final `push` call is only locally mutating the array. During the phase that looks at local mutations we are only tracking direct aliases, and the push doesn't directly alias the items to the array, it only captures them.

[ghstack-poisoned]
2025-05-28 22:27:20 -07:00
Joe Savona c207ff562a [compiler] First example of an aliasing signature (array push)
Adds an aliasing signature for Array.prototype.push and fixes up the logic for consuming these signatures during effect inference. As the test fixture shows, we correctly model the capturing. Mutable values that are captured into the array count as co-mutated if the array itself is transitively mutated later, while mutable values captured after such transitive mutation are not considered co-mutated.

The implementation is based on the fact that the final `push` call is only locally mutating the array. During the phase that looks at local mutations we are only tracking direct aliases, and the push doesn't directly alias the items to the array, it only captures them.

[ghstack-poisoned]
2025-05-28 17:38:49 -07:00
Joe Savona cdd2d3f2f9 Update on "[compiler] Delay mutation of function expr context variables until function is called"
See comments in code. The idea is that rather than immediately processing function expression effects when declaring the function, we record Capture effects for context variables that may be captured/mutated in the function. Then, transitive mutations of the function value itself will extend the range of these values via the normal captured value comutation inference established earlier in the stack (if capture a -> b, then transitiveMutate(b) => mutate(a)). So capture contextVar -> function and transitiveMutate(function) => mutate(contextVar).

[ghstack-poisoned]
2025-05-28 17:38:47 -07:00
Joe Savona 51d5aa3f33 Update base for Update on "[compiler] Delay mutation of function expr context variables until function is called"
See comments in code. The idea is that rather than immediately processing function expression effects when declaring the function, we record Capture effects for context variables that may be captured/mutated in the function. Then, transitive mutations of the function value itself will extend the range of these values via the normal captured value comutation inference established earlier in the stack (if capture a -> b, then transitiveMutate(b) => mutate(a)). So capture contextVar -> function and transitiveMutate(function) => mutate(contextVar).

[ghstack-poisoned]
2025-05-28 17:38:46 -07:00
Joe Savona 8c70807cec [compiler] Delay mutation of function expr context variables until function is called
See comments in code. The idea is that rather than immediately processing function expression effects when declaring the function, we record Capture effects for context variables that may be captured/mutated in the function. Then, transitive mutations of the function value itself will extend the range of these values via the normal captured value comutation inference established earlier in the stack (if capture a -> b, then transitiveMutate(b) => mutate(a)). So capture contextVar -> function and transitiveMutate(function) => mutate(contextVar).

[ghstack-poisoned]
2025-05-28 16:29:32 -07:00
Joe Savona a219df1c98 Update on "[compiler] Add ImmutableCapture effect, CreateFrom no longer needs Capture"
ImmutableCapture allows us to record information flow for escape analysis purposes, without impacting mutable range analysis. All of Alias, Capture, and CreateFrom now downgrade to ImmutableCapture if the `from` value is frozen. Globals and primitives are conceptually copy types and don't record any information flow at all. I guess we could add a `Copy` effect if we wanted but i haven't seen a need for it yet.

Related, previously CreateFrom was always paired with Capture when constructing effects. But I had also coded up the inference to sort of treat them the same. So this diff makes that official, and means CreateFrom is a valid third way to represent data flow and not just creation. When applied, CreateFrom will turn into: ImmutableCapture for frozen values, Capture for mutable values, and disappear for globals/primitives.

A final tweak is to change range inference to ensure that range.start is non-zero if the value is mutated.

[ghstack-poisoned]
2025-05-28 16:29:30 -07:00
Joe Savona 1a733b8946 Update base for Update on "[compiler] Add ImmutableCapture effect, CreateFrom no longer needs Capture"
ImmutableCapture allows us to record information flow for escape analysis purposes, without impacting mutable range analysis. All of Alias, Capture, and CreateFrom now downgrade to ImmutableCapture if the `from` value is frozen. Globals and primitives are conceptually copy types and don't record any information flow at all. I guess we could add a `Copy` effect if we wanted but i haven't seen a need for it yet.

Related, previously CreateFrom was always paired with Capture when constructing effects. But I had also coded up the inference to sort of treat them the same. So this diff makes that official, and means CreateFrom is a valid third way to represent data flow and not just creation. When applied, CreateFrom will turn into: ImmutableCapture for frozen values, Capture for mutable values, and disappear for globals/primitives.

A final tweak is to change range inference to ensure that range.start is non-zero if the value is mutated.

[ghstack-poisoned]
2025-05-28 16:29:30 -07:00
Joe Savona 74c236a99d [compiler] Add ImmutableCapture effect, CreateFrom no longer needs Capture
ImmutableCapture allows us to record information flow for escape analysis purposes, without impacting mutable range analysis. All of Alias, Capture, and CreateFrom now downgrade to ImmutableCapture if the `from` value is frozen. Globals and primitives are conceptually copy types and don't record any information flow at all. I guess we could add a `Copy` effect if we wanted but i haven't seen a need for it yet.

Related, previously CreateFrom was always paired with Capture when constructing effects. But I had also coded up the inference to sort of treat them the same. So this diff makes that official, and means CreateFrom is a valid third way to represent data flow and not just creation. When applied, CreateFrom will turn into: ImmutableCapture for frozen values, Capture for mutable values, and disappear for globals/primitives.

A final tweak is to change range inference to ensure that range.start is non-zero if the value is mutated.

[ghstack-poisoned]
2025-05-28 15:42:38 -07:00
Joe Savona f9bb6067ab Update on "[compiler] Improve inference of function expression mutation/aliasing effects"
Distinguish the various forms of mutation, and do basic replaying of these effects when the function is created (imperfect, temporary).

[ghstack-poisoned]
2025-05-28 15:42:36 -07:00