Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: facebook/react
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 94e652d5
Choose a base ref
...
head repository: facebook/react
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 206df66e
Choose a head ref
  • 5 commits
  • 129 files changed
  • 2 contributors

Commits on Sep 12, 2024

  1. Enable lazy context propagation (#30935)

    Last I heard this was great so not sure there are any more blockers to
    just include it in 19?
    sebmarkbage authored Sep 12, 2024
    Configuration menu
    Copy the full SHA
    89b4457 View commit details
    Browse the repository at this point in the history
  2. [Flight] Track owner/stack where the Flight Client reads as the root (#…

    …30933)
    
    This means that the owner of a Component rendered on the remote server
    becomes the Component on this server.
    
    Ideally we'd support this for the Client side too. In particular Fiber
    but currently ReactComponentInfo's owner is typed as only supporting
    other ReactComponentInfo and it's a bigger lift to support that.
    sebmarkbage authored Sep 12, 2024
    Configuration menu
    Copy the full SHA
    dff5082 View commit details
    Browse the repository at this point in the history
  3. [compiler][ez] Add entrypoints to ssa fixtures

    Adds evaluator support for a few compiler test fixtures
    
    ghstack-source-id: 2026549
    Pull Request resolved: #30948
    mofeiZ committed Sep 12, 2024
    Configuration menu
    Copy the full SHA
    f6dcce5 View commit details
    Browse the repository at this point in the history
  4. [compiler] Fork fixtures for enablePropagateDepsInHIR

    - flip `enablePropagateDepsInHIR` to off by default
    - fork fixtures which produce compilation differences in #30894 to separate directory `propagate-scope-deps-hir-fork`, to be cleaned up when we remove this flag
    
    ghstack-source-id: 7d5b8dc
    Pull Request resolved: #30949
    mofeiZ committed Sep 12, 2024
    Configuration menu
    Copy the full SHA
    5ac4034 View commit details
    Browse the repository at this point in the history
  5. [compiler][rewrite] PropagateScopeDeps hir rewrite

    Resubmission of #30079 -- core logic unchanged, but needed to rebase past #30573
    
    ### Quick background
    #### Temporaries
    
    The compiler currently treats temporaries and named variables (e.g. `x`) differently in this pass.
    - named variables may be reassigned (in fact, since we're running after LeaveSSA, a single named identifier's IdentifierId may map to multiple `Identifier` instances -- each with its own scope and mutable range)
    - temporaries are replaced with their represented expressions during codegen. This is correct (mostly correct, see #29878) as we're careful to always lower the correct evaluation semantics. However, since we rewrite reactive scopes entirely (to if/else blocks), we need to track temporaries that a scope produces in `ReactiveScope.declarations` and later promote them to named variables.
    In the same example, $4, $5, and $6 need to be promoted: $2 ->`t0`,  $5 ->`t1`, and $6 ->`t2`.
    ```js
    [1] $2 = LoadGlobal(global) foo
    [2] $3 = LoadLocal bar$1
    scope 0:
      [3] $4 = Call $2(<unknown> $3)
    scope 1:
      [4] $5 = Object {  }
    scope 2:
      [5] $6 = Object { a: $4, b: $5 }
    [6] $8 = StoreLocal Const x$7 = $6
    ```
    
    #### Dependencies
    `ReactiveScope.dependencies` records the set of (read-only) values that a reactive scope is dependent on. This is currently limited to just variables (named variables from source and promoted temporaries) and property-loads.
    All dependencies we record need to be hoistable -- i.e. reordered to just before the ReactiveScope begins. Not all PropertyLoads are hoistable.
    
    In this example, we should not evaluate `obj.a.b` without before creating x and checking `objIsNull`.
    ```js
    // reduce-reactive-deps/no-uncond.js
    function useFoo({ obj, objIsNull }) {
      const x = [];
      if (isFalse(objIsNull)) {
        x.push(obj.a.b);
      }
      return x;
    }
    ```
    
    While other memoization strategies with different constraints exist, the current compiler requires that `ReactiveScope.dependencies` be re-orderable to the beginning of the reactive scope. But.. `PropertyLoad`s from null values will throw `TypeError`. This means that evaluating hoisted dependencies should throw if and only if the source program throws. (It is also a bug if source throws and compiler output does not throw. See facebook/react-forget#2709)
    
    ---
    ### Rough high level overview
    1. Pass 1
    Walk over instructions to gather every temporary used outside of its defining scope (same as ReactiveFunction version). These determine the sidemaps we produce, as temporaries used outside of their declaring scopes get promoted to named variables later (and are not considered hoistable rvals).
    2. Pass 2 (collectTemporariesSidemap)
    Walk over instructions to generate a sidemap of temporary identifier -> named variable and property path (e.g. `$3 -> {obj: props, path: ["a", "b"]}`)
    2. Pass 2 (collectHoistablePropertyLoads)
      a. Build a sidemap of block -> accessed variables and properties (e.g. `bb0 -> [ {obj: props, path: ["a", "b"]} ]`)
      b. Propagate "non-nullness" i.e. variables and properties for which we can safely evaluate `PropertyLoad`.
      A basic block can unconditionally read from identifier X if any of the following applies:
        - the block itself reads from identifier X
        - all predecessors of the block read from identifier X
        - all successors of the block read from identifier X
    4. Pass 3: (collectDependencies)
    Walks over instructions again to record dependencies and declarations, using the previously produced sidemaps. We do not record any control-flow here
    5. Merge every scope's recorded dependencies with the set of hoistable PropertyLoads
    
    Tested by syncing internally and (1) checking compilation output differences ([internal link](https://www.internalfb.com/intern/everpaste/?handle=GPCfUBt_HCoy_S4EAJDVFJyJJMR0bsIXAAAB)), running internally e2e tests ([internal link](https://fburl.com/sandcastle/cs5mlkxq))
    
    ---
    ### Followups:
    1. Rewrite function expression deps
    This change produces much more optimal output as the compiler now uses the function CFG to understand which variables / paths are assumed to be non-null. However, it may exacerbate [this function-expr hoisting bug](https://github.com/facebook/react/blob/main/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-hoisting-functionexpr.tsx). A short term fix here is to simply call some form of `collectNonNullObjects` on every function expression to find hoistable variable / paths. In the longer term, we should refactor out `FunctionExpression.deps`.
    
    2. Enable optional paths
    (a) don't count optional load temporaries as dependencies (e.g. `collectOptionalLoadRValues(...)`).
    (b) record optional paths in both collectHoistablePropertyLoads and dependency collection
    
    ghstack-source-id: 2507f6e
    Pull Request resolved: #30894
    mofeiZ committed Sep 12, 2024
    Configuration menu
    Copy the full SHA
    206df66 View commit details
    Browse the repository at this point in the history
Loading