Summary:
I generated the following program (now added to test cases) and while I would expect its evaluation in Prepack to terminate reasonably quickly, I did not see the program terminate after five minutes of execution:
https://gist.github.com/calebmer/2bf1d84a5b7849fa732bce69811df10b
After this change that same program’s Prepack evaluation terminates in about two seconds. This change also saves about 2.8s on the evaluation of our internal bundle which is about 3% of the total time.
What was happening? Why did my program fail to terminate execution in five minutes? Why was the internal bundle relatively ok compared to my extreme case?
In my program, I would [expect the component `Mu`](https://gist.github.com/calebmer/2bf1d84a5b7849fa732bce69811df10b#file-program-js-L289-L291) to be inlined about 60 times. Which means there should only be about 60 calls to `ReactElementSet#add` for each of `Mu`’s `div`s. However, after some basic instrumentation I observed way over ten thousand visits to these React elements.
This pair of method calls happens a couple times in `ReactEquivalenceSet` and friends.
5f7256f17e/src/react/ReactEquivalenceSet.js (L233-L234)
Both `getEquivalentPropertyValue`…
5f7256f17e/src/react/ReactEquivalenceSet.js (L255)
…and `getValue`…
5f7256f17e/src/react/ReactEquivalenceSet.js (L104)
…end up calling `ReactElementSet#add` with the same React element. Then `ReactElementSet#add` ends up recursing into children. So the root element is added 2 times, so the root’s children are added 4 times each, so each child of those elements are added 8 times each, and so on. So if a leaf element is `n` deep in the tree it will be added `2^n` times. The most nested `Mu` child was 9 elements deep. `Mu` appeared 60 times at many levels of nesting.
I’m not entirely sure why my generated case was so much worse then our internal bundle. My two best guesses are: lots of repeated components or deeper nesting?
My fix was to move the `getValue` call into `getEquivalentPropertyValue`. This way if `getEquivalentPropertyValue` already finds an equivalent value we can short-circuit and not run `getValue` which will perform the same operation.
Pull Request resolved: https://github.com/facebook/prepack/pull/2243
Reviewed By: trueadm
Differential Revision: D8811463
Pulled By: calebmer
fbshipit-source-id: 4f30a75e96c6592456f5b21ee9c2ee3e40b56d81
Summary:
This adds a React-specific internal test for Prepack to fbsource. It's meant to be land-blocking.
I checked in a manually edited bundle that has no dependencies except `react` and `react-dom` (so it's not too difficult to maintain). I also checked in a snapshot test for what it should render.
The test step consists of running the Jest test (to verify it works *before* Prepack), then using the existing `debug-fb-www` command to produce a bundle, and finally running the same Jest test again.
Currently this only checks the initialization path. When render path serializer bugs are fixed, we can run the same bundle in the render mode as well (and catch further regressions).
Reviewed By: NTillmann
Differential Revision: D7675812
fbshipit-source-id: 99fe3bd700ae3557ee6245f1e8e1e835399625b5
Summary:
The [website publication script](https://github.com/facebook/prepack/blob/master/scripts/publish-gh-pages.sh) creates a temporary directory (`build`) to fetch fresh copies of the `master` and `gh-pages` branches.
This temporary directory is not removed and causes `flow` to check it when running `yarn flow`, causing many errors.
To address this issue, this PR:
- Changes the publication script to clean up temporary directories at the end of its execution
- Renames the temporary directory name from `build` to `tmp_website_build` to make it clearer that it can be safely removed, should the script fail to remove it
- Changes `.gitignore` and `.flowconfig` to ignore the temporary directory, should the script fail to remove it
Thanks to hermanventer for reporting the issue
Closes https://github.com/facebook/prepack/pull/1302
Differential Revision: D6648852
Pulled By: j-nolan
fbshipit-source-id: 099963bf6907ff7e69301acafcfb3aeedfbb5b20
Summary:
Break up, simplify and refine path conditions. Also special case the property values obtained from joined objects to use the object's join condition, which is more likely to match the a path condition than the artificial "ob === ob1 ? ob1.prop : ob2.prop" that arises from the general case.
Finally, beef up the implementation of implies, to handle more complicated path conditions by breaking up && and || conditions.
Closes https://github.com/facebook/prepack/pull/970
Differential Revision: D5857033
Pulled By: hermanventer
fbshipit-source-id: 5436d251378decf6de549a3d70e9605664d569e5
Summary:
We usually need at least two files: 1) the environmental model and 2) the bundle to be Prepacked.
In general, there is no good reason to not allow as many files as the caller wants.
To make this not be a breaking chance, I've added a new API for this: prepackSources.
Further complications result from working around a bug in Babel and not increasing the module cycle length for Flow.
Closes https://github.com/facebook/prepack/pull/776
Differential Revision: D5366190
Pulled By: hermanventer
fbshipit-source-id: 74595b1b60e8e8a6d24cb974b5be10210d745266
This moves things around in a more common idiomatic folder structure / naming convention. This extracts the scripts that are only used to test the library from the source of the library itself.
/src/scripts -> /scripts
This is no longer part of the build process. Therefore we use babel-node to run the files as needed. The exception is test-runner that is just ran in plain node so that it works with the coverage reports.
The lib folder now includes only and all the library files required to use the package and no longer test runners.
Because of that I moved all the dependencies that were related only to our test scripts and website build to devDependencies. That way we minimize the required dependencies to use Prepack downstream as an npm package.
Then I configured the package.json to only list lib/ and bin/ folders as part of the package. This lets `npm publish` ignore all other files so that people installing the package don't need to include all our testing code.
I added files to bin/ and package.json which is a convention to make this package installable and usable as a command-line tool.
Renamed run_util -> prepack-cli and repl -> repl-cli to separate these from library variants.
The coverage reports now get created in the root instead of lib folder so that they don't get included in the build.
I bumped the version number to one minor above what is already on npm since we can't publish earlier than that.